summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-11-18 12:44:31 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-11-18 12:45:29 +0100
commit99a8ec6e24d2788bb533ab5be8618a958adf24cf (patch)
treefc9424f45d66014b80d65b1eabee83d09956ea6a
parent79a606bd95abcceda3da668819426ddb583f7c56 (diff)
downloadphp-git-99a8ec6e24d2788bb533ab5be8618a958adf24cf.tar.gz
Short-circuit get_gc for currently running generator
-rw-r--r--Zend/tests/generators/gc_running_generator.phpt25
-rw-r--r--Zend/zend_generators.c10
2 files changed, 35 insertions, 0 deletions
diff --git a/Zend/tests/generators/gc_running_generator.phpt b/Zend/tests/generators/gc_running_generator.phpt
new file mode 100644
index 0000000000..e702381b62
--- /dev/null
+++ b/Zend/tests/generators/gc_running_generator.phpt
@@ -0,0 +1,25 @@
+--TEST--
+GC on running generator
+--FILE--
+<?php
+
+function gen() {
+ yield;
+ // Trigger GC while $v is being reassigned.
+ $ary = [new stdClass, new stdClass, new stdClass];
+ $ary[0]->foo = $ary;
+ foreach ($ary as &$v) { }
+}
+
+for ($i = 0; $i < 10000; $i++) {
+ // Make sure gen is registered as a GC root.
+ $gen = gen();
+ $gen2 = $gen;
+ unset($gen);
+ foreach ($gen2 as $v) {}
+}
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 805bff38ab..3fbbd49c0a 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -340,6 +340,16 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
return NULL;
}
+ if (generator->flags & ZEND_GENERATOR_CURRENTLY_RUNNING) {
+ /* If the generator is currently running, we certainly won't be able to GC any values it
+ * holds on to. The execute_data state might be inconsistent during execution (e.g. because
+ * GC has been triggered in the middle of a variable reassignment), so we should not try
+ * to inspect it here. */
+ *table = NULL;
+ *n = 0;
+ return NULL;
+ }
+
op_array = &EX(func)->op_array;
gc_buffer_size = calc_gc_buffer_size(generator);
if (generator->gc_buffer_size < gc_buffer_size) {