summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-07-01 12:03:13 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-07-01 15:17:26 +0200
commit271bc689ea9211821363e289accb23bb965aa5eb (patch)
treea3180532e6e6992ea6b15ca3bce0f0b992087c5f /Zend
parent312201dce4daca2770fd507af4a9a541bfe83fc0 (diff)
downloadphp-git-271bc689ea9211821363e289accb23bb965aa5eb.tar.gz
Add iterator get_gc function for generators
Closes GH-5787.
Diffstat (limited to 'Zend')
-rw-r--r--Zend/tests/generators/iterator_wrapper_leak.phpt33
-rw-r--r--Zend/zend_generators.c10
2 files changed, 42 insertions, 1 deletions
diff --git a/Zend/tests/generators/iterator_wrapper_leak.phpt b/Zend/tests/generators/iterator_wrapper_leak.phpt
new file mode 100644
index 0000000000..bc0f34e9c8
--- /dev/null
+++ b/Zend/tests/generators/iterator_wrapper_leak.phpt
@@ -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
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index b1abbd7f9b..fe7066c0c8 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -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) /* {{{ */