[php-src] master: Merge branch 'PHP-8.5' into PHP-8.6

From: Date: Wed, 30 Sep 2026 17:51:09 +0000
Subject: [php-src] master: Merge branch 'PHP-8.5' into PHP-8.6
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-141813@lists.php.net to get a copy of this message
Author: Ilia Alshanetsky (iliaal) Date: 2026-09-30T13:28:19-04:00 Commit: https://github.com/php/php-src/commit/c4a1e63074cdc61f190d7af215d16baa3ab7d09b Raw diff: https://github.com/php/php-src/commit/c4a1e63074cdc61f190d7af215d16baa3ab7d09b.diff Merge branch 'PHP-8.5' into PHP-8.6 * PHP-8.5: ext/pdo: Report bound params and columns to GC Changed paths: A ext/pdo/tests/get_gc_bound_params.phpt M NEWS M ext/pdo/pdo_stmt.c Diff: diff --git a/NEWS b/NEWS index 810a69982a79..36ae20791bb0 100644 --- a/NEWS +++ b/NEWS @@ -77,6 +77,8 @@ PHP NEWS "array given" regardless of the value passed. (Ilia Alshanetsky) . Fixed PDOStatement::bindParam() and bindColumn() leaking the driver options value. (Ilia Alshanetsky) + . Fixed PDOStatement not reporting its bound parameters and columns to the + cycle collector. (Ilia Alshanetsky) . Fixed PDOStatement::execute() leaving the previous result available after a failed execution. (Ilia Alshanetsky) . Fixed a use-after-free when bindValue()/execute()/closeCursor() is called diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index c08c093974ae..0b1dc91923a9 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2041,6 +2041,22 @@ static HashTable *dbstmt_get_gc(zend_object *object, zval **gc_data, int *gc_cou } else if (default_fetch_mode == PDO_FETCH_CLASS && stmt->fetch.cls.ctor_args != NULL) { zend_get_gc_buffer_add_ht(gc_buffer, stmt->fetch.cls.ctor_args); } + if (stmt->bound_params) { + zval *val; + ZEND_HASH_FOREACH_VAL(stmt->bound_params, val) { + struct pdo_bound_param_data *param = Z_PTR_P(val); + zend_get_gc_buffer_add_zval(gc_buffer, &param->parameter); + zend_get_gc_buffer_add_zval(gc_buffer, &param->driver_params); + } ZEND_HASH_FOREACH_END(); + } + if (stmt->bound_columns) { + zval *val; + ZEND_HASH_FOREACH_VAL(stmt->bound_columns, val) { + struct pdo_bound_param_data *param = Z_PTR_P(val); + zend_get_gc_buffer_add_zval(gc_buffer, &param->parameter); + zend_get_gc_buffer_add_zval(gc_buffer, &param->driver_params); + } ZEND_HASH_FOREACH_END(); + } zend_get_gc_buffer_use(gc_buffer, gc_data, gc_count); /** diff --git a/ext/pdo/tests/get_gc_bound_params.phpt b/ext/pdo/tests/get_gc_bound_params.phpt new file mode 100644 index 000000000000..01c824a477c0 --- /dev/null +++ b/ext/pdo/tests/get_gc_bound_params.phpt @@ -0,0 +1,66 @@ +--TEST-- +PDO Common: PDOStatement::get_gc() must report bound params and columns for cycle collection +--EXTENSIONS-- +pdo +--SKIPIF-- +<?php +$dir = getenv('REDIR_TEST_DIR'); +if (false == $dir) die('skip no driver'); +require_once $dir . 'pdo_test.inc'; +PDOTest::skip(); +?> +--FILE-- +<?php +if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/'); +require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; + +class Tracked { + public static array $collected = []; + + public function __construct(public string $name, public PDOStatement $stmt) {} + + public function __destruct() { + self::$collected[] = $this->name; + } +} + +$db = PDOTest::factory(); +$db->exec('CREATE TABLE get_gc_bound_params (a INT, b INT)'); + +$insert = $db->prepare('INSERT INTO get_gc_bound_params VALUES (?, ?)'); +$param = new Tracked('param', $insert); +$insert->bindParam(1, $param, PDO::PARAM_INT); +$paramOption = null; +$insert->bindParam(2, $paramOption, PDO::PARAM_INT, 0, new Tracked('param driver option', $insert)); + +$select = $db->query('SELECT a, b FROM get_gc_bound_params'); +$column = new Tracked('column', $select); +$select->bindColumn(1, $column, PDO::PARAM_INT); +$columnOption = null; +$select->bindColumn(2, $columnOption, PDO::PARAM_INT, 0, new Tracked('column driver option', $select)); + +unset($param, $paramOption, $column, $columnOption, $insert, $select, $db); +var_dump(Tracked::$collected); +gc_collect_cycles(); +sort(Tracked::$collected); +var_dump(Tracked::$collected); +?> +--CLEAN-- +<?php +require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; +$db = PDOTest::factory(); +PDOTest::dropTableIfExists($db, 'get_gc_bound_params'); +?> +--EXPECT-- +array(0) { +} +array(4) { + [0]=> + string(6) "column" + [1]=> + string(20) "column driver option" + [2]=> + string(5) "param" + [3]=> + string(19) "param driver option" +}

« previous php.cvs (#141813) next »