summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Weinand <bobwei9@hotmail.com>2016-04-18 23:54:41 +0200
committerBob Weinand <bobwei9@hotmail.com>2016-04-18 23:55:16 +0200
commit5085352464e55e92cd5bb7beeb2284b2e1b78061 (patch)
tree821398aefb88e2ca15723db032c9f985f1dde7d5
parentea1f30057b50b24c83750b8d5410108b7ba65180 (diff)
downloadphp-git-5085352464e55e92cd5bb7beeb2284b2e1b78061.tar.gz
Fix generator being a cycle to itself
-rw-r--r--Zend/tests/generators/gc_with_yield_from.phpt45
-rw-r--r--Zend/zend_generators.c8
2 files changed, 49 insertions, 4 deletions
diff --git a/Zend/tests/generators/gc_with_yield_from.phpt b/Zend/tests/generators/gc_with_yield_from.phpt
new file mode 100644
index 0000000000..8c05561990
--- /dev/null
+++ b/Zend/tests/generators/gc_with_yield_from.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Verify yield from on generators being properly cycle collected
+--FILE--
+<?php
+
+function root() {
+ global $gens; // create cyclic reference to root
+ try {
+ yield 1;
+ } finally {
+ var_dump($gens);
+ }
+}
+
+function gen($x) {
+ global $gens;
+ yield from $gens[] = $x ? gen(--$x) : root();
+}
+
+$gen = $gens[] = gen(2);
+var_dump($gen->current());
+unset($gen, $gens);
+print "collect\n";
+gc_collect_cycles();
+print "end\n";
+
+?>
+--EXPECT--
+int(1)
+collect
+array(4) {
+ [0]=>
+ object(Generator)#1 (0) {
+ }
+ [1]=>
+ object(Generator)#2 (0) {
+ }
+ [2]=>
+ object(Generator)#3 (0) {
+ }
+ [3]=>
+ object(Generator)#4 (0) {
+ }
+}
+end
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index e2cc2382bd..33f187c96f 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -220,10 +220,10 @@ static uint32_t calc_gc_buffer_size(zend_generator *generator) /* {{{ */
/* Yield from root references */
if (generator->node.children == 0) {
- zend_generator *root = generator->node.ptr.root;
- while (root != generator) {
+ zend_generator *child = generator, *root = generator->node.ptr.root;
+ while (root != child) {
+ child = child->node.parent;
size++;
- root = zend_generator_get_child(&root->node, generator);
}
}
}
@@ -287,8 +287,8 @@ 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) {
- ZVAL_OBJ(gc_buffer++, &child->std);
child = child->node.parent;
+ ZVAL_OBJ(gc_buffer++, &child->std);
}
}