Skip to content

Commit 63e1e32

Browse files
committed
Fix GH-16131: Prevent mixing PDO sub-classes with different DSN
1 parent 341c26f commit 63e1e32

23 files changed

+211
-31
lines changed

ext/pdo/pdo_dbh.c

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -237,45 +237,64 @@ static bool create_driver_specific_pdo_object(pdo_driver_t *driver, zend_class_e
237237
if (ce_based_on_driver_name) {
238238
if (instanceof_function(ce_based_on_called_object, ce_based_on_driver_name) == false) {
239239
zend_throw_exception_ex(pdo_exception_ce, 0,
240-
"%s::connect() cannot be called when connecting to the \"%s\" driver, "
241-
"either %s::connect() or PDO::connect() must be called instead",
242-
ZSTR_VAL(called_scope->name), driver->driver_name, ZSTR_VAL(ce_based_on_driver_name->name));
240+
"%s::%s() cannot be called when connecting to the \"%s\" driver, "
241+
"either call %s::%s() or PDO::%s() instead",
242+
ZSTR_VAL(called_scope->name),
243+
new_object ? "connect" : "__construct",
244+
driver->driver_name,
245+
ZSTR_VAL(ce_based_on_driver_name->name),
246+
new_object ? "connect" : "__construct",
247+
new_object ? "connect" : "__construct"
248+
);
243249
return false;
244250
}
245251

246-
/* A driver-specific implementation was instantiated via the connect() method of the appropriate driver class */
247-
object_init_ex(new_object, ce_based_on_called_object);
252+
/* A driver-specific implementation is instantiated with the appropriate driver class */
253+
if (new_object) {
254+
object_init_ex(new_object, ce_based_on_called_object);
255+
}
248256
return true;
249257
} else {
250258
zend_throw_exception_ex(pdo_exception_ce, 0,
251-
"%s::connect() cannot be called when connecting to an unknown driver, "
252-
"PDO::connect() must be called instead",
253-
ZSTR_VAL(called_scope->name));
259+
"%s::%s() cannot be called when connecting to an unknown driver, "
260+
"call PDO::%s() instead",
261+
ZSTR_VAL(called_scope->name),
262+
new_object ? "connect" : "__construct",
263+
new_object ? "connect" : "__construct"
264+
);
254265
return false;
255266
}
256267
}
257268

258269
if (ce_based_on_driver_name) {
259270
if (called_scope != pdo_dbh_ce) {
260-
/* A driver-specific implementation was instantiated via the connect method of a wrong driver class */
271+
/* A driver-specific implementation is instantiated of a wrong driver class */
261272
zend_throw_exception_ex(pdo_exception_ce, 0,
262-
"%s::connect() cannot be called when connecting to the \"%s\" driver, "
263-
"either %s::connect() or PDO::connect() must be called instead",
264-
ZSTR_VAL(called_scope->name), driver->driver_name, ZSTR_VAL(ce_based_on_driver_name->name));
273+
"%s::%s() cannot be called when connecting to the \"%s\" driver, "
274+
"either call %s::%s() or PDO::%s() instead",
275+
ZSTR_VAL(called_scope->name),
276+
new_object ? "connect" : "__construct",
277+
driver->driver_name,
278+
ZSTR_VAL(ce_based_on_driver_name->name),
279+
new_object ? "connect" : "__construct",
280+
new_object ? "connect" : "__construct"
281+
);
265282
return false;
266283
}
267284

268285
/* A driver-specific implementation was instantiated via PDO::__construct() */
269-
object_init_ex(new_object, ce_based_on_driver_name);
270-
} else {
286+
if (new_object) {
287+
object_init_ex(new_object, ce_based_on_driver_name);
288+
}
289+
} else if (new_object) {
271290
/* No driver-specific implementation found */
272291
object_init_ex(new_object, called_scope);
273292
}
274293

275294
return true;
276295
}
277296

278-
static void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object, zend_class_entry *current_scope, zval *new_zval_object)
297+
PDO_API void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object, zend_class_entry *current_scope, zval *new_zval_object)
279298
{
280299
pdo_dbh_t *dbh = NULL;
281300
bool is_persistent = 0;
@@ -343,12 +362,13 @@ static void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object
343362
RETURN_THROWS();
344363
}
345364

346-
if (new_zval_object != NULL) {
347-
ZEND_ASSERT((driver->driver_name != NULL) && "PDO driver name is null");
348-
if (!create_driver_specific_pdo_object(driver, current_scope, new_zval_object)) {
349-
RETURN_THROWS();
350-
}
365+
ZEND_ASSERT((driver->driver_name != NULL) && "PDO driver name is null");
366+
367+
if (!create_driver_specific_pdo_object(driver, current_scope, new_zval_object)) {
368+
RETURN_THROWS();
369+
}
351370

371+
if (new_zval_object) {
352372
dbh = Z_PDO_DBH_P(new_zval_object);
353373
} else {
354374
dbh = php_pdo_dbh_fetch_inner(object);
@@ -497,7 +517,7 @@ static void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object
497517
/* {{{ */
498518
PHP_METHOD(PDO, __construct)
499519
{
500-
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), EX(This).value.ce, NULL);
520+
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
501521
}
502522
/* }}} */
503523

ext/pdo/php_pdo_driver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,8 @@ PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh);
694694
PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt);
695695
PDO_API void php_pdo_stmt_set_column_count(pdo_stmt_t *stmt, int new_count);
696696

697+
PDO_API void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object, zend_class_entry *current_scope, zval *new_zval_object);
698+
697699
/* Normalization for fetching long param for driver attributes */
698700
PDO_API bool pdo_get_long_param(zend_long *lval, zval *value);
699701
PDO_API bool pdo_get_bool_param(bool *bval, zval *value);

ext/pdo_dblib/pdo_dblib.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "php_pdo_dblib.h"
2828
#include "php_pdo_dblib_int.h"
2929
#include "zend_exceptions.h"
30+
#include "zend_attributes.h"
3031
#include "pdo_dblib_arginfo.h"
3132

3233
ZEND_DECLARE_MODULE_GLOBALS(dblib)
@@ -241,3 +242,8 @@ PHP_MINFO_FUNCTION(pdo_dblib)
241242
php_info_print_table_row(2, "Flavour", PDO_DBLIB_FLAVOUR);
242243
php_info_print_table_end();
243244
}
245+
246+
PHP_METHOD(Pdo_Dblib, __construct)
247+
{
248+
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
249+
}

ext/pdo_dblib/pdo_dblib.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ class Dblib extends \PDO
3030

3131
/** @cvalue PDO_DBLIB_ATTR_DATETIME_CONVERT */
3232
public const int ATTR_DATETIME_CONVERT = UNKNOWN;
33+
34+
public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}
3335
}

ext/pdo_dblib/pdo_dblib_arginfo.h

Lines changed: 19 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/pdo_firebird/pdo_firebird.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "ext/pdo/php_pdo_driver.h"
2626
#include "php_pdo_firebird.h"
2727
#include "php_pdo_firebird_int.h"
28+
#include "zend_attributes.h"
2829
#include "pdo_firebird_arginfo.h"
2930

3031
static zend_class_entry *PdoFirebird_ce;
@@ -101,6 +102,11 @@ PHP_MINFO_FUNCTION(pdo_firebird) /* {{{ */
101102
}
102103
/* }}} */
103104

105+
PHP_METHOD(Pdo_Firebird, __construct)
106+
{
107+
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
108+
}
109+
104110
PHP_METHOD(Pdo_Firebird, getApiVersion)
105111
{
106112
if (zend_parse_parameters_none() == FAILURE) {

ext/pdo_firebird/pdo_firebird.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,7 @@ class Firebird extends \PDO
3434
/** @cvalue PDO_FB_WRITABLE_TRANSACTION */
3535
public const int WRITABLE_TRANSACTION = UNKNOWN;
3636

37+
public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}
38+
3739
public static function getApiVersion(): int {}
3840
}

ext/pdo_firebird/pdo_firebird_arginfo.h

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/pdo_mysql/pdo_mysql.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "ext/pdo/php_pdo_driver.h"
2727
#include "php_pdo_mysql.h"
2828
#include "php_pdo_mysql_int.h"
29+
#include "zend_attributes.h"
2930
#include "pdo_mysql_arginfo.h"
3031

3132
static zend_class_entry *pdo_mysql_ce;
@@ -84,6 +85,11 @@ static const MYSQLND_REVERSE_API pdo_mysql_reverse_api = {
8485
};
8586
#endif
8687

88+
PHP_METHOD(Pdo_Mysql, __construct)
89+
{
90+
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
91+
}
92+
8793
/* Returns the number of SQL warnings during the execution of the last statement */
8894
PHP_METHOD(Pdo_Mysql, getWarningCount)
8995
{

ext/pdo_mysql/pdo_mysql.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,7 @@ class Mysql extends \PDO
7373
public const int ATTR_LOCAL_INFILE_DIRECTORY = UNKNOWN;
7474
#endif
7575

76+
public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}
77+
7678
public function getWarningCount(): int {}
7779
}

ext/pdo_mysql/pdo_mysql_arginfo.h

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/pdo_odbc/pdo_odbc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "ext/pdo/php_pdo_driver.h"
2626
#include "php_pdo_odbc.h"
2727
#include "php_pdo_odbc_int.h"
28+
#include "zend_attributes.h"
2829
#include "pdo_odbc_arginfo.h"
2930

3031
static zend_class_entry *pdo_odbc_ce;
@@ -61,6 +62,11 @@ zend_ulong pdo_odbc_pool_on = SQL_CP_OFF;
6162
zend_ulong pdo_odbc_pool_mode = SQL_CP_ONE_PER_HENV;
6263
#endif
6364

65+
PHP_METHOD(Pdo_Odbc, __construct)
66+
{
67+
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
68+
}
69+
6470
/* {{{ PHP_MINIT_FUNCTION */
6571
PHP_MINIT_FUNCTION(pdo_odbc)
6672
{

ext/pdo_odbc/pdo_odbc.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,7 @@ class Odbc extends \PDO
3131

3232
/** @cvalue SQL_CUR_USE_ODBC */
3333
public const int SQL_USE_ODBC = UNKNOWN;
34+
35+
public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}
3436
}
3537
}

ext/pdo_odbc/pdo_odbc_arginfo.h

Lines changed: 19 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/pdo_pgsql/pdo_pgsql.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "ext/pdo/php_pdo_driver.h"
2727
#include "php_pdo_pgsql.h"
2828
#include "php_pdo_pgsql_int.h"
29+
#include "zend_attributes.h"
2930
#include "pdo_pgsql_arginfo.h"
3031

3132
static zend_class_entry *PdoPgsql_ce;
@@ -57,6 +58,11 @@ zend_module_entry pdo_pgsql_module_entry = {
5758
ZEND_GET_MODULE(pdo_pgsql)
5859
#endif
5960

61+
PHP_METHOD(Pdo_Pgsql, __construct)
62+
{
63+
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
64+
}
65+
6066
/* Escape an identifier for insertion into a text field */
6167
PHP_METHOD(Pdo_Pgsql, escapeIdentifier)
6268
{

ext/pdo_pgsql/pdo_pgsql.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class Pgsql extends \PDO
3333
/** @cvalue PGSQL_TRANSACTION_UNKNOWN */
3434
public const int TRANSACTION_UNKNOWN = UNKNOWN;
3535

36+
public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}
37+
3638
public function escapeIdentifier(string $input): string {}
3739

3840
public function copyFromArray(string $tableName, array $rows, string $separator = "\t", string $nullAs = "\\\\N", ?string $fields = null): bool {}

0 commit comments

Comments
 (0)