Skip to content

Commit 99a8ec6

Browse files
committed
Short-circuit get_gc for currently running generator
1 parent 79a606b commit 99a8ec6

File tree

2 files changed

+35
-0
lines changed

2 files changed

+35
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
GC on running generator
3+
--FILE--
4+
<?php
5+
6+
function gen() {
7+
yield;
8+
// Trigger GC while $v is being reassigned.
9+
$ary = [new stdClass, new stdClass, new stdClass];
10+
$ary[0]->foo = $ary;
11+
foreach ($ary as &$v) { }
12+
}
13+
14+
for ($i = 0; $i < 10000; $i++) {
15+
// Make sure gen is registered as a GC root.
16+
$gen = gen();
17+
$gen2 = $gen;
18+
unset($gen);
19+
foreach ($gen2 as $v) {}
20+
}
21+
22+
?>
23+
===DONE===
24+
--EXPECT--
25+
===DONE===

Zend/zend_generators.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,16 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
340340
return NULL;
341341
}
342342

343+
if (generator->flags & ZEND_GENERATOR_CURRENTLY_RUNNING) {
344+
/* If the generator is currently running, we certainly won't be able to GC any values it
345+
* holds on to. The execute_data state might be inconsistent during execution (e.g. because
346+
* GC has been triggered in the middle of a variable reassignment), so we should not try
347+
* to inspect it here. */
348+
*table = NULL;
349+
*n = 0;
350+
return NULL;
351+
}
352+
343353
op_array = &EX(func)->op_array;
344354
gc_buffer_size = calc_gc_buffer_size(generator);
345355
if (generator->gc_buffer_size < gc_buffer_size) {

0 commit comments

Comments
 (0)