Skip to content

Commit f03f4db

Browse files
committed
Root current opline result after GC, delay GC run until safepoint
1 parent 4191843 commit f03f4db

17 files changed

+308
-78
lines changed

Zend/tests/gc/bug70805.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ $i = 0;
2828
$c = new A;
2929
$array = array($c); //This is used to leave a room for $GLOBALS["a"]
3030
unset($c);
31+
flush(); // handle interrupts
3132

3233
while ($i++ < 9998) {
3334
$t = [];
@@ -37,11 +38,13 @@ while ($i++ < 9998) {
3738
$t = [new C];
3839
$t[] = &$t;
3940
unset($t); // This is used to trigger C::__destruct while doing gc_collect_roots
41+
flush(); // handle interrupts
4042

4143
$e = $a;
4244
unset($a); // This one cannot be put into roots buf because it's full, thus gc_collect_roots will be called,
4345
// but C::__destructor which is called in gc_collect_roots will put $a into buf
4446
// which will make $a be put into gc roots buf twice
47+
flush(); // handle interrupts
4548
var_dump(gc_collect_cycles());
4649
?>
4750
--EXPECT--

Zend/tests/gc/bug70805_1.phpt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ $i = 0;
3030
$c = new A;
3131
$array = array($c);
3232
unset($c);
33+
flush(); // handle interrupts
3334

3435
while ($i++ < 9998) {
3536
$t = [];
@@ -39,9 +40,11 @@ while ($i++ < 9998) {
3940
$t = [new C];
4041
$t[] = &$t;
4142
unset($t);
43+
flush(); // handle interrupts
4244
unset($a);
45+
flush(); // handle interrupts
4346

4447
var_dump(gc_collect_cycles());
4548
?>
4649
--EXPECT--
47-
int(2)
50+
int(0)

Zend/tests/gc/bug70805_2.phpt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@ while ($i++ < 9999) {
3131
$t[] = &$t;
3232
unset($t);
3333
}
34+
flush(); // handle interrupts
3435
$t = [new C];
3536
$t[] = &$t;
3637
unset($t);
38+
flush(); // handle interrupts
3739

3840
unset($a);
41+
flush(); // handle interrupts
3942
var_dump(gc_collect_cycles());
4043
?>
4144
--EXPECT--
42-
int(2)
45+
int(0)

Zend/tests/gc/gc_023.phpt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,23 @@ for ($i=0; $i < 9999; $i++) {
1111
}
1212
var_dump(gc_collect_cycles());
1313
unset($a);
14+
flush(); // handle interrupts
1415
var_dump(gc_collect_cycles());
1516
$a=array();
1617
for ($i=0; $i < 10001; $i++) {
1718
$a[$i] = array(array());
1819
$a[$i][0] = & $a[$i];
1920
}
21+
flush(); // handle interrupts
2022
var_dump(gc_collect_cycles());
21-
unset($a); // 10000 zvals collected automatic
23+
unset($a);
24+
flush(); // handle interrupts. 10000 zvals collected automatic
2225
var_dump(gc_collect_cycles());
2326
echo "ok\n";
2427
?>
2528
--EXPECT--
2629
int(0)
2730
int(9999)
2831
int(0)
29-
int(1)
32+
int(0)
3033
ok

Zend/tests/gc/gc_045.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ array(12) {
5656
["runs"]=>
5757
int(10)
5858
["collected"]=>
59-
int(25000)
59+
int(25005)
6060
["threshold"]=>
6161
int(10001)
6262
["buffer_size"]=>
63-
int(16384)
63+
int(%d)
6464
["roots"]=>
65-
int(10000)
65+
int(9990)
6666
["application_time"]=>
6767
float(%f)
6868
["collector_time"]=>

Zend/tests/gc/gh13687-001.phpt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
GH-13687 001: Result operand may leak if GC is triggered before consumption
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public $cycle;
8+
public function __construct() { $this->cycle = $this; }
9+
}
10+
class B {
11+
public function get() {
12+
return new A();
13+
}
14+
}
15+
16+
$c = new B();
17+
$objs = [];
18+
19+
while (gc_status()['roots']+2 < gc_status()['threshold']) {
20+
$obj = new stdClass;
21+
$objs[] = $obj;
22+
}
23+
24+
var_dump($c->get());
25+
26+
?>
27+
--EXPECTF--
28+
object(A)#%d (1) {
29+
["cycle"]=>
30+
*RECURSION*
31+
}

Zend/tests/gc/gh13687-002.phpt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
GH-13687 002: Result operand may leak if GC is triggered before consumption
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public $cycle;
8+
public function __construct() { $this->cycle = $this; }
9+
public function __toString() { return __CLASS__; }
10+
}
11+
class B {
12+
public function get() {
13+
return new A();
14+
}
15+
}
16+
17+
$root = new stdClass;
18+
gc_collect_cycles();
19+
20+
$objs = [];
21+
while (gc_status()['roots']+2 < gc_status()['threshold']) {
22+
$obj = new stdClass;
23+
$objs[] = $obj;
24+
}
25+
26+
$a = [new A, $root][0]::class;
27+
28+
?>
29+
==DONE==
30+
--EXPECT--
31+
==DONE==

Zend/tests/gc/gh13687-003.phpt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
GH-13687 003: Result operand may leak if GC is triggered before consumption
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public $cycle;
8+
public function __construct() { $this->cycle = $this; }
9+
}
10+
class B {
11+
public function get() {
12+
return new A();
13+
}
14+
}
15+
class Debug {
16+
public function __debugInfo() {
17+
gc_collect_cycles();
18+
return [];
19+
}
20+
}
21+
22+
$c = new B();
23+
var_dump($c->get(), new Debug);
24+
25+
?>
26+
==DONE==
27+
--EXPECTF--
28+
object(A)#%d (1) {
29+
["cycle"]=>
30+
*RECURSION*
31+
}
32+
object(Debug)#%d (0) {
33+
}
34+
==DONE==

Zend/tests/gc/gh13687-004.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-13687 004: Result operand may leak if GC is triggered before consumption
3+
--ENV--
4+
func=call_user_func
5+
--FILE--
6+
<?php
7+
8+
class A {
9+
public $cycle;
10+
public function __construct() { $this->cycle = $this; }
11+
}
12+
class B {
13+
public function get() {
14+
return new A();
15+
}
16+
}
17+
class Debug {
18+
public function __debugInfo() {
19+
gc_collect_cycles();
20+
return [];
21+
}
22+
}
23+
24+
$c = new B();
25+
getenv('func')(fn (...$args) => gc_collect_cycles(), a: $c->get());
26+
27+
?>
28+
==DONE==
29+
--EXPECT--
30+
==DONE==

Zend/zend_builtin_functions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ ZEND_FUNCTION(gc_collect_cycles)
167167
{
168168
ZEND_PARSE_PARAMETERS_NONE();
169169

170-
RETURN_LONG(gc_collect_cycles());
170+
RETURN_LONG(gc_collect_cycles(0));
171171
}
172172
/* }}} */
173173

0 commit comments

Comments
 (0)