From a5f137821ade6f2068ffa11a143b81ecb7acccb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 5 Nov 2024 08:32:44 +0100 Subject: [PATCH] Fix GH-16314 "Pdo\Mysql object is uninitialized" when opening a persistent connection (#16369) --- NEWS | 2 + ext/pdo/pdo_dbh.c | 10 +++- ext/pdo/tests/pdo_test.inc | 12 ++-- ext/pdo_mysql/tests/gh16314.phpt | 62 +++++++++++++++++++++ ext/pdo_mysql/tests/inc/mysql_pdo_test.inc | 9 ++- ext/pdo_pgsql/tests/gh16314.phpt | 65 ++++++++++++++++++++++ 6 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 ext/pdo_mysql/tests/gh16314.phpt create mode 100644 ext/pdo_pgsql/tests/gh16314.phpt diff --git a/NEWS b/NEWS index 17884e5774836..4a11a82696c10 100644 --- a/NEWS +++ b/NEWS @@ -47,6 +47,8 @@ PHP NEWS - PDO: . Fixed bug GH-16167 (Prevent mixing PDO sub-classes with different DSN). (kocsismate) + . Fixed bug GH-16314 ("Pdo\Mysql object is uninitialized" when opening a + persistent connection). (kocsismate) - PDO_ODBC: . Fixed bug GH-16450 (PDO_ODBC can inject garbage into field values). (cmb) diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 68673d1544af7..782639be0758e 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -436,8 +436,16 @@ PDO_API void php_pdo_internal_construct_driver(INTERNAL_FUNCTION_PARAMETERS, zen if (pdbh) { efree(dbh); + + pdo_dbh_object_t *pdo_obj; + if (new_zval_object) { + pdo_obj = Z_PDO_OBJECT_P(new_zval_object); + } else { + pdo_obj = php_pdo_dbh_fetch_object(current_object); + } + /* switch over to the persistent one */ - php_pdo_dbh_fetch_object(current_object)->inner = pdbh; + pdo_obj->inner = pdbh; pdbh->refcount++; dbh = pdbh; } diff --git a/ext/pdo/tests/pdo_test.inc b/ext/pdo/tests/pdo_test.inc index 5138452ff9c51..0c5d5412a273f 100644 --- a/ext/pdo/tests/pdo_test.inc +++ b/ext/pdo/tests/pdo_test.inc @@ -18,7 +18,7 @@ if (getenv('PDOTEST_DSN') === false) { class PDOTest { // create an instance of the PDO driver, based on // the current environment - static function factory($classname = PDO::class) { + static function factory($classname = PDO::class, bool $useConnectMethod = false) { $dsn = getenv('PDOTEST_DSN'); $user = getenv('PDOTEST_USER'); $pass = getenv('PDOTEST_PASS'); @@ -32,7 +32,11 @@ class PDOTest { if ($user === false) $user = NULL; if ($pass === false) $pass = NULL; - $db = new $classname($dsn, $user, $pass, $attr); + if ($useConnectMethod) { + $db = $classname::connect($dsn, $user, $pass, $attr); + } else { + $db = new $classname($dsn, $user, $pass, $attr); + } if (!$db) { die("Could not create PDO object (DSN=$dsn, user=$user)\n"); @@ -54,12 +58,12 @@ class PDOTest { } } - static function test_factory($file, $classname = PDO::class) { + static function test_factory($file, $classname = PDO::class, bool $useConnectMethod = false) { $config = self::get_config($file); foreach ($config['ENV'] as $k => $v) { putenv("$k=$v"); } - return self::factory($classname); + return self::factory($classname, $useConnectMethod); } static function get_config($file) { diff --git a/ext/pdo_mysql/tests/gh16314.phpt b/ext/pdo_mysql/tests/gh16314.phpt new file mode 100644 index 0000000000000..65da24bd28edb --- /dev/null +++ b/ext/pdo_mysql/tests/gh16314.phpt @@ -0,0 +1,62 @@ +--TEST-- +GH-16314 "Pdo\Mysql object is uninitialized" when opening a persistent connection +--EXTENSIONS-- +pdo_mysql +--SKIPIF-- + +--FILE-- + true], false); +var_dump($pdo->query('SELECT 1;')->fetchAll()); + +$pdo = MySQLPDOTest::factory(Pdo\Mysql::class, null, [PDO::ATTR_PERSISTENT => true], true); +var_dump($pdo->query('SELECT 1;')->fetchAll()); + +$pdo = MySQLPDOTest::factory(Pdo::class, null, [PDO::ATTR_PERSISTENT => true], false); +var_dump($pdo->query('SELECT 1;')->fetchAll()); + +$pdo = MySQLPDOTest::factory(Pdo::class, null, [PDO::ATTR_PERSISTENT => true], true); +var_dump($pdo->query('SELECT 1;')->fetchAll()); +?> +--EXPECT-- +array(1) { + [0]=> + array(2) { + [1]=> + int(1) + [0]=> + int(1) + } +} +array(1) { + [0]=> + array(2) { + [1]=> + int(1) + [0]=> + int(1) + } +} +array(1) { + [0]=> + array(2) { + [1]=> + int(1) + [0]=> + int(1) + } +} +array(1) { + [0]=> + array(2) { + [1]=> + int(1) + [0]=> + int(1) + } +} diff --git a/ext/pdo_mysql/tests/inc/mysql_pdo_test.inc b/ext/pdo_mysql/tests/inc/mysql_pdo_test.inc index 48a7c525a7016..75f299ff9e198 100644 --- a/ext/pdo_mysql/tests/inc/mysql_pdo_test.inc +++ b/ext/pdo_mysql/tests/inc/mysql_pdo_test.inc @@ -8,7 +8,7 @@ foreach ($env as $k => $v) { class MySQLPDOTest extends PDOTest { - static function factory($classname = PDO::class, $mydsn = null, $myAttr = null) { + static function factory($classname = PDO::class, $mydsn = null, $myAttr = null, bool $useConnectMethod = false) { $dsn = self::getDSN($mydsn); $user = PDO_MYSQL_TEST_USER; $pass = PDO_MYSQL_TEST_PASS; @@ -20,7 +20,12 @@ class MySQLPDOTest extends PDOTest { $attr = is_string($attr) && strlen($attr) ? unserialize($attr) : null; } - $db = new $classname($dsn, $user, $pass, $attr); + if ($useConnectMethod) { + $db = $classname::connect($dsn, $user, $pass, $attr); + } else { + $db = new $classname($dsn, $user, $pass, $attr); + } + if (!$db) { die("Could not create PDO object (DSN=$dsn, user=$user)\n"); } diff --git a/ext/pdo_pgsql/tests/gh16314.phpt b/ext/pdo_pgsql/tests/gh16314.phpt new file mode 100644 index 0000000000000..0dde12a4e0e3d --- /dev/null +++ b/ext/pdo_pgsql/tests/gh16314.phpt @@ -0,0 +1,65 @@ +--TEST-- +GH-16314 "Pdo\Pgsql object is uninitialized" when opening a persistent connection +--EXTENSIONS-- +pdo_pgsql +--SKIPIF-- + +--FILE-- + true])); + +require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; + +$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt', Pdo\Pgsql::class, false); +var_dump($pdo->query('SELECT 1;')->fetchAll()); + +$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt', Pdo\Pgsql::class, true); +var_dump($pdo->query('SELECT 1;')->fetchAll()); + +$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt', Pdo::class, false); +var_dump($pdo->query('SELECT 1;')->fetchAll()); + +$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt', Pdo::class, true); +var_dump($pdo->query('SELECT 1;')->fetchAll()); +?> +--EXPECT-- +array(1) { + [0]=> + array(2) { + ["?column?"]=> + string(1) "1" + [0]=> + string(1) "1" + } +} +array(1) { + [0]=> + array(2) { + ["?column?"]=> + string(1) "1" + [0]=> + string(1) "1" + } +} +array(1) { + [0]=> + array(2) { + ["?column?"]=> + string(1) "1" + [0]=> + string(1) "1" + } +} +array(1) { + [0]=> + array(2) { + ["?column?"]=> + string(1) "1" + [0]=> + string(1) "1" + } +}