summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/generators/gc_with_root_parent_mismatch.phpt27
-rw-r--r--Zend/zend_generators.c14
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);
}
}