[php-src] PHP-8.4: Fix GH-24050: gc_collect_white() frees data reachable from a resurrected object

From: Date: Fri, 02 Oct 2026 10:18:40 +0000
Subject: [php-src] PHP-8.4: Fix GH-24050: gc_collect_white() frees data reachable from a resurrected object
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-141875@lists.php.net to get a copy of this message
Author: David Carlier (devnexen) Date: 2026-10-02T11:16:06+01:00 Commit: https://github.com/php/php-src/commit/7b75d71ca3f6c3226f7feffcc25247091b4d8c9e Raw diff: https://github.com/php/php-src/commit/7b75d71ca3f6c3226f7feffcc25247091b4d8c9e.diff Fix GH-24050: gc_collect_white() frees data reachable from a resurrected object A properties table shared through a cast got no garbage slot, so nested data removal stopped at it before the destructor ran. Close GH-24061 Changed paths: A Zend/tests/gh24050.phpt A Zend/tests/gh24050_2.phpt M NEWS M Zend/zend_gc.c Diff: diff --git a/NEWS b/NEWS index edeca96eaebd..7b24c94899c9 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,8 @@ PHP NEWS function and a later request calls it. (Ilia Alshanetsky) . Fixed System V shared memory emulation for Windows attaching segments past the end of their mapping. (Ilia Alshanetsky) + . Fixed bug GH-24050 (GC frees an object still held by a resurrected closure + when (object) and use share an array). (David Carlier) - DOM: . Fixed use-after-free when re-constructing a DOMXPath whose php:function 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 ffd427eac5bc..669a009defe7 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -1517,6 +1517,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_REFCOUNTED_P(zv)) { ref = Z_COUNTED_P(zv);

« previous php.cvs (#141875) next »