diff options
-rw-r--r-- | Zend/tests/generators/gc_with_root_parent_mismatch.phpt | 27 | ||||
-rw-r--r-- | Zend/zend_generators.c | 14 |
2 files changed, 34 insertions, 7 deletions
diff --git a/Zend/tests/generators/gc_with_root_parent_mismatch.phpt b/Zend/tests/generators/gc_with_root_parent_mismatch.phpt new file mode 100644 index 0000000000..ee388b1c76 --- /dev/null +++ b/Zend/tests/generators/gc_with_root_parent_mismatch.phpt @@ -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) diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index a932f405e2..9242269906 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -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); } } |