]> granicus.if.org Git - php/commitdiff
Add iterator get_gc function for generators
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 1 Jul 2020 10:03:13 +0000 (12:03 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 1 Jul 2020 13:17:26 +0000 (15:17 +0200)
Closes GH-5787.

Zend/tests/generators/iterator_wrapper_leak.phpt [new file with mode: 0644]
Zend/zend_generators.c

diff --git a/Zend/tests/generators/iterator_wrapper_leak.phpt b/Zend/tests/generators/iterator_wrapper_leak.phpt
new file mode 100644 (file)
index 0000000..bc0f34e
--- /dev/null
@@ -0,0 +1,33 @@
+--TEST--
+A generator iterator wrapper involved in a cycle should not leak
+--FILE--
+<?php
+
+class Test {
+    public function method() {
+        $this->gen1 = (function () {
+            yield 1;
+            yield 2;
+            yield 3;
+        })();
+        $gen2 = function() {
+            foreach ($this->gen1 as $x) {
+                echo "$x\n";
+                yield $x;
+            }
+        };
+        $this->gen2 = $gen2();
+        foreach ($this->gen2 as $x) {
+            if ($x == 2) {
+                break;
+            }
+        }
+    }
+}
+(new Test)->method();
+gc_collect_cycles();
+
+?>
+--EXPECT--
+1
+2
index b1abbd7f9bea36d9f85ac7028d920e7af129b199..fe7066c0c835f498973cd7f7436fe326c629356d 100644 (file)
@@ -1087,6 +1087,14 @@ static void zend_generator_iterator_rewind(zend_object_iterator *iterator) /* {{
 }
 /* }}} */
 
+static HashTable *zend_generator_iterator_get_gc(
+               zend_object_iterator *iterator, zval **table, int *n)
+{
+       *table = &iterator->data;
+       *n = 1;
+       return NULL;
+}
+
 static const zend_object_iterator_funcs zend_generator_iterator_functions = {
        zend_generator_iterator_dtor,
        zend_generator_iterator_valid,
@@ -1095,7 +1103,7 @@ static const zend_object_iterator_funcs zend_generator_iterator_functions = {
        zend_generator_iterator_move_forward,
        zend_generator_iterator_rewind,
        NULL,
-       NULL, /* get_gc */
+       zend_generator_iterator_get_gc,
 };
 
 zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */