Skip to content

Commit 03bf9cd

Browse files
committed
Merge branch 'PHP-8.6'
* PHP-8.6: Fix GH-24050: gc_collect_white() frees data reachable from a resurrected object
2 parents e7e46c1 + 3ebd95f commit 03bf9cd

3 files changed

Lines changed: 101 additions & 0 deletions

File tree

‎Zend/tests/gh24050.phpt‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
--TEST--
2+
GH-24050 (GC frees an object still held by a resurrected closure when (object) and use share an array)
3+
--CREDITS--
4+
OllieCrook
5+
--FILE--
6+
<?php
7+
8+
class Resurrector
9+
{
10+
public $closure;
11+
public $self;
12+
13+
public function __destruct()
14+
{
15+
$GLOBALS['resurrected'] = $this->closure;
16+
}
17+
}
18+
19+
class Holder
20+
{
21+
public $castObject;
22+
public $resurrector;
23+
public $self;
24+
}
25+
26+
$array = ['victim' => new stdClass(), 'key' => 'value'];
27+
28+
$holder = new Holder();
29+
$resurrector = new Resurrector();
30+
$holder->castObject = (object) $array;
31+
$resurrector->closure = function () use ($array) {
32+
return $array;
33+
};
34+
$holder->resurrector = $resurrector;
35+
$holder->self = $holder;
36+
$resurrector->self = $resurrector;
37+
38+
unset($array);
39+
gc_collect_cycles();
40+
41+
unset($holder, $resurrector);
42+
gc_collect_cycles();
43+
gc_collect_cycles();
44+
45+
var_dump($resurrected()['victim']);
46+
?>
47+
--EXPECT--
48+
object(stdClass)#1 (0) {
49+
}

‎Zend/tests/gh24050_2.phpt‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
--TEST--
2+
GH-24050 (GC frees an object still held by a resurrected closure when (array) and use share a properties table)
3+
--FILE--
4+
<?php
5+
6+
class Resurrector
7+
{
8+
public $closure;
9+
public $self;
10+
11+
public function __destruct()
12+
{
13+
$GLOBALS['resurrected'] = $this->closure;
14+
}
15+
}
16+
17+
class Holder
18+
{
19+
public $obj;
20+
public $resurrector;
21+
public $self;
22+
}
23+
24+
$obj = new stdClass();
25+
$obj->victim = new stdClass();
26+
27+
$holder = new Holder();
28+
$resurrector = new Resurrector();
29+
$holder->obj = $obj;
30+
$array = (array) $obj;
31+
$resurrector->closure = function () use ($array) {
32+
return $array;
33+
};
34+
$holder->resurrector = $resurrector;
35+
$holder->self = $holder;
36+
$resurrector->self = $resurrector;
37+
38+
unset($array, $obj);
39+
gc_collect_cycles();
40+
41+
unset($holder, $resurrector);
42+
gc_collect_cycles();
43+
gc_collect_cycles();
44+
45+
var_dump($resurrected()['victim']);
46+
?>
47+
--EXPECT--
48+
object(stdClass)#2 (0) {
49+
}

‎Zend/zend_gc.c‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,9 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_stack *sta
15741574
GC_ADDREF(ht);
15751575
if (GC_REF_CHECK_COLOR(ht, GC_WHITE)) {
15761576
GC_REF_SET_BLACK(ht);
1577+
if (!GC_INFO(ht)) {
1578+
gc_add_garbage((zend_refcounted *)ht);
1579+
}
15771580
for (; n != 0; n--) {
15781581
if (Z_COLLECTABLE_P(zv)) {
15791582
ref = Z_COUNTED_P(zv);

0 commit comments

Comments
 (0)