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

From: Date: Fri, 02 Oct 2026 10:18:43 +0000
Subject: [php-src] master: Merge branch 'PHP-8.6'
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-141878@lists.php.net to get a copy of this message
Author: David Carlier (devnexen) Date: 2026-10-02T11:18:29+01:00 Commit: https://github.com/php/php-src/commit/03bf9cdcac9ac5f6b7164e4a8670a838e1ded6dd Raw diff: https://github.com/php/php-src/commit/03bf9cdcac9ac5f6b7164e4a8670a838e1ded6dd.diff Merge branch 'PHP-8.6' * PHP-8.6: Fix GH-24050: gc_collect_white() frees data reachable from a resurrected object Changed paths: A Zend/tests/gh24050.phpt A Zend/tests/gh24050_2.phpt M Zend/zend_gc.c Diff: diff --git a/Zend/tests/gh24050.phpt b/Zend/tests/gh24050.phpt new file mode 100644 index 000000000000..d5c77fa43dd8 --- /dev/null +++ b/Zend/tests/gh24050.phpt @@ -0,0 +1,49 @@ +--TEST-- +GH-24050 (GC frees an object still held by a resurrected closure when (object) and use share an array) +--CREDITS-- +OllieCrook +--FILE-- +<?php + +class Resurrector +{ + public $closure; + public $self; + + public function __destruct() + { + $GLOBALS['resurrected'] = $this->closure; + } +} + +class Holder +{ + public $castObject; + public $resurrector; + public $self; +} + +$array = ['victim' => new stdClass(), 'key' => 'value']; + +$holder = new Holder(); +$resurrector = new Resurrector(); +$holder->castObject = (object) $array; +$resurrector->closure = function () use ($array) { + return $array; +}; +$holder->resurrector = $resurrector; +$holder->self = $holder; +$resurrector->self = $resurrector; + +unset($array); +gc_collect_cycles(); + +unset($holder, $resurrector); +gc_collect_cycles(); +gc_collect_cycles(); + +var_dump($resurrected()['victim']); +?> +--EXPECT-- +object(stdClass)#1 (0) { +} diff --git a/Zend/tests/gh24050_2.phpt b/Zend/tests/gh24050_2.phpt new file mode 100644 index 000000000000..a4f49d96a4e8 --- /dev/null +++ b/Zend/tests/gh24050_2.phpt @@ -0,0 +1,49 @@ +--TEST-- +GH-24050 (GC frees an object still held by a resurrected closure when (array) and use share a properties table) +--FILE-- +<?php + +class Resurrector +{ + public $closure; + public $self; + + public function __destruct() + { + $GLOBALS['resurrected'] = $this->closure; + } +} + +class Holder +{ + public $obj; + public $resurrector; + public $self; +} + +$obj = new stdClass(); +$obj->victim = new stdClass(); + +$holder = new Holder(); +$resurrector = new Resurrector(); +$holder->obj = $obj; +$array = (array) $obj; +$resurrector->closure = function () use ($array) { + return $array; +}; +$holder->resurrector = $resurrector; +$holder->self = $holder; +$resurrector->self = $resurrector; + +unset($array, $obj); +gc_collect_cycles(); + +unset($holder, $resurrector); +gc_collect_cycles(); +gc_collect_cycles(); + +var_dump($resurrected()['victim']); +?> +--EXPECT-- +object(stdClass)#2 (0) { +} diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index 6c7e2a728e93..6372ed0550c8 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -1574,6 +1574,9 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_stack *sta GC_ADDREF(ht); if (GC_REF_CHECK_COLOR(ht, GC_WHITE)) { GC_REF_SET_BLACK(ht); + if (!GC_INFO(ht)) { + gc_add_garbage((zend_refcounted *)ht); + } for (; n != 0; n--) { if (Z_COLLECTABLE_P(zv)) { ref = Z_COUNTED_P(zv);

« previous php.cvs (#141878) next »