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

From: Date: Wed, 30 Sep 2026 17:51:12 +0000
Subject: [php-src] master: Merge branch 'PHP-8.6'
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-141814@lists.php.net to get a copy of this message
Author: Ilia Alshanetsky (iliaal) Date: 2026-09-30T13:28:22-04:00 Commit: https://github.com/php/php-src/commit/6387fc5674408738f65ea42477850d8ea1da7d8a Raw diff: https://github.com/php/php-src/commit/6387fc5674408738f65ea42477850d8ea1da7d8a.diff Merge branch 'PHP-8.6' * PHP-8.6: ext/pdo: Report bound params and columns to GC Changed paths: A ext/pdo/tests/get_gc_bound_params.phpt M ext/pdo/pdo_stmt.c Diff: diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 758226957ce6..7d25427a0d42 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2036,6 +2036,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 (#141814) next »