mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Fix generator GC if yield from parent chain does not reach root
Parents may be unlinked while another generator sharing part of the chain is running. As such, we cannot assume that the parent chain goes all the way to the root. Instead walk backwards from root to leaf, like we also do during destruction.
This commit is contained in:
parent
cab0a814bd
commit
8c07170ddb
2 changed files with 34 additions and 7 deletions
27
Zend/tests/generators/gc_with_root_parent_mismatch.phpt
Normal file
27
Zend/tests/generators/gc_with_root_parent_mismatch.phpt
Normal file
|
@ -0,0 +1,27 @@
|
|||
--TEST--
|
||||
Generator GC when the yield from parent chain does not reach the root
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function root() {
|
||||
yield 1;
|
||||
yield 2;
|
||||
}
|
||||
|
||||
function delegate($gen) {
|
||||
yield from $gen;
|
||||
}
|
||||
|
||||
$gen = delegate(delegate(root()));
|
||||
$gen1 = delegate(delegate($gen));
|
||||
$gen2 = delegate(delegate($gen));
|
||||
var_dump($gen1->current());
|
||||
var_dump($gen2->current());
|
||||
$gen1->next();
|
||||
$gen1->next();
|
||||
gc_collect_cycles();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(1)
|
||||
int(1)
|
|
@ -276,9 +276,9 @@ static uint32_t calc_gc_buffer_size(zend_generator *generator) /* {{{ */
|
|||
|
||||
/* Yield from root references */
|
||||
if (generator->node.children == 0) {
|
||||
zend_generator *child = generator, *root = generator->node.ptr.root;
|
||||
while (root != child) {
|
||||
child = child->node.parent;
|
||||
zend_generator *root = generator->node.ptr.root;
|
||||
while (root != generator) {
|
||||
root = zend_generator_get_child(&root->node, generator);
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
@ -341,10 +341,10 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
|
|||
}
|
||||
|
||||
if (generator->node.children == 0) {
|
||||
zend_generator *child = generator, *root = generator->node.ptr.root;
|
||||
while (root != child) {
|
||||
child = child->node.parent;
|
||||
ZVAL_OBJ(gc_buffer++, &child->std);
|
||||
zend_generator *root = generator->node.ptr.root;
|
||||
while (root != generator) {
|
||||
ZVAL_OBJ(gc_buffer++, &root->std);
|
||||
root = zend_generator_get_child(&root->node, generator);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue