Fix GH-16314 "Pdo\Mysql object is uninitialized" when opening a persistent connection (#16369)

This commit is contained in:
Máté Kocsis 2024-11-05 08:32:44 +01:00 committed by GitHub
parent fd1dff988e
commit a5f137821a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 153 additions and 7 deletions

2
NEWS
View file

@ -47,6 +47,8 @@ PHP NEWS
- PDO: - PDO:
. Fixed bug GH-16167 (Prevent mixing PDO sub-classes with different DSN). . Fixed bug GH-16167 (Prevent mixing PDO sub-classes with different DSN).
(kocsismate) (kocsismate)
. Fixed bug GH-16314 ("Pdo\Mysql object is uninitialized" when opening a
persistent connection). (kocsismate)
- PDO_ODBC: - PDO_ODBC:
. Fixed bug GH-16450 (PDO_ODBC can inject garbage into field values). (cmb) . Fixed bug GH-16450 (PDO_ODBC can inject garbage into field values). (cmb)

View file

@ -436,8 +436,16 @@ PDO_API void php_pdo_internal_construct_driver(INTERNAL_FUNCTION_PARAMETERS, zen
if (pdbh) { if (pdbh) {
efree(dbh); 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 */ /* switch over to the persistent one */
php_pdo_dbh_fetch_object(current_object)->inner = pdbh; pdo_obj->inner = pdbh;
pdbh->refcount++; pdbh->refcount++;
dbh = pdbh; dbh = pdbh;
} }

View file

@ -18,7 +18,7 @@ if (getenv('PDOTEST_DSN') === false) {
class PDOTest { class PDOTest {
// create an instance of the PDO driver, based on // create an instance of the PDO driver, based on
// the current environment // the current environment
static function factory($classname = PDO::class) { static function factory($classname = PDO::class, bool $useConnectMethod = false) {
$dsn = getenv('PDOTEST_DSN'); $dsn = getenv('PDOTEST_DSN');
$user = getenv('PDOTEST_USER'); $user = getenv('PDOTEST_USER');
$pass = getenv('PDOTEST_PASS'); $pass = getenv('PDOTEST_PASS');
@ -32,7 +32,11 @@ class PDOTest {
if ($user === false) $user = NULL; if ($user === false) $user = NULL;
if ($pass === false) $pass = NULL; if ($pass === false) $pass = NULL;
if ($useConnectMethod) {
$db = $classname::connect($dsn, $user, $pass, $attr);
} else {
$db = new $classname($dsn, $user, $pass, $attr); $db = new $classname($dsn, $user, $pass, $attr);
}
if (!$db) { if (!$db) {
die("Could not create PDO object (DSN=$dsn, user=$user)\n"); 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); $config = self::get_config($file);
foreach ($config['ENV'] as $k => $v) { foreach ($config['ENV'] as $k => $v) {
putenv("$k=$v"); putenv("$k=$v");
} }
return self::factory($classname); return self::factory($classname, $useConnectMethod);
} }
static function get_config($file) { static function get_config($file) {

View file

@ -0,0 +1,62 @@
--TEST--
GH-16314 "Pdo\Mysql object is uninitialized" when opening a persistent connection
--EXTENSIONS--
pdo_mysql
--SKIPIF--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
MySQLPDOTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
$pdo = MySQLPDOTest::factory(Pdo\Mysql::class, null, [PDO::ATTR_PERSISTENT => 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)
}
}

View file

@ -8,7 +8,7 @@ foreach ($env as $k => $v) {
class MySQLPDOTest extends PDOTest { 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); $dsn = self::getDSN($mydsn);
$user = PDO_MYSQL_TEST_USER; $user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS; $pass = PDO_MYSQL_TEST_PASS;
@ -20,7 +20,12 @@ class MySQLPDOTest extends PDOTest {
$attr = is_string($attr) && strlen($attr) ? unserialize($attr) : null; $attr = is_string($attr) && strlen($attr) ? unserialize($attr) : null;
} }
if ($useConnectMethod) {
$db = $classname::connect($dsn, $user, $pass, $attr);
} else {
$db = new $classname($dsn, $user, $pass, $attr); $db = new $classname($dsn, $user, $pass, $attr);
}
if (!$db) { if (!$db) {
die("Could not create PDO object (DSN=$dsn, user=$user)\n"); die("Could not create PDO object (DSN=$dsn, user=$user)\n");
} }

View file

@ -0,0 +1,65 @@
--TEST--
GH-16314 "Pdo\Pgsql object is uninitialized" when opening a persistent connection
--EXTENSIONS--
pdo_pgsql
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
putenv('PDOTEST_ATTR='.serialize([PDO::ATTR_PERSISTENT => 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"
}
}