summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2018-09-28 19:14:47 +0200
committerNikita Popov <nikita.ppv@gmail.com>2018-09-28 19:15:19 +0200
commit83e2b9e2202da6cc25bdaac67a58022b90be88e7 (patch)
tree3ea01fc88cefcc05a28e11c6294beb4e5a517c25
parent69c1b619c9d6a20dd5a50a058659c5c4233aea82 (diff)
downloadphp-git-83e2b9e2202da6cc25bdaac67a58022b90be88e7.tar.gz
Fixed bug #76946
-rw-r--r--NEWS2
-rw-r--r--Zend/tests/bug76946.phpt27
-rw-r--r--Zend/zend_generators.c36
3 files changed, 65 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 0edbe6112c..5b5cfb64b2 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2018, PHP 7.1.24
+- Core:
+ . Fixed bug #76946 (Cyclic reference in generator not detected). (Nikita)
11 Oct 2018, PHP 7.1.23
diff --git a/Zend/tests/bug76946.phpt b/Zend/tests/bug76946.phpt
new file mode 100644
index 0000000000..e04724fd54
--- /dev/null
+++ b/Zend/tests/bug76946.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #76946: Cyclic reference in generator not detected
+--FILE--
+<?php
+
+function gen() {
+ $gen = yield;
+ foreach ([1, $gen] as $v) {
+ yield $v;
+ }
+}
+
+function gen2() {
+ $gen = yield;
+ $gen + yield;
+}
+
+$gen = gen();
+$gen->send($gen);
+
+$gen2 = gen2();
+$gen2->send($gen2);
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 9242269906..a3b56eda74 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -274,6 +274,25 @@ static uint32_t calc_gc_buffer_size(zend_generator *generator) /* {{{ */
size += Z_TYPE(execute_data->This) == IS_OBJECT; /* $this */
size += (EX_CALL_INFO() & ZEND_CALL_CLOSURE) != 0; /* Closure object */
+ /* Live vars */
+ if (execute_data->opline != op_array->opcodes) {
+ /* -1 required because we want the last run opcode, not the next to-be-run one. */
+ uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
+ for (i = 0; i < op_array->last_live_range; i++) {
+ const zend_live_range *range = &op_array->live_range[i];
+ if (range->start > op_num) {
+ /* Further ranges will not be relevant... */
+ break;
+ } else if (op_num < range->end) {
+ /* LIVE_ROPE and LIVE_SILENCE not relevant for GC */
+ uint32_t kind = range->var & ZEND_LIVE_MASK;
+ if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) {
+ size++;
+ }
+ }
+ }
+ }
+
/* Yield from root references */
if (generator->node.children == 0) {
zend_generator *root = generator->node.ptr.root;
@@ -340,6 +359,23 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
ZVAL_OBJ(gc_buffer++, (zend_object *) EX(func)->common.prototype);
}
+ if (execute_data->opline != op_array->opcodes) {
+ uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
+ for (i = 0; i < op_array->last_live_range; i++) {
+ const zend_live_range *range = &op_array->live_range[i];
+ if (range->start > op_num) {
+ break;
+ } else if (op_num < range->end) {
+ uint32_t kind = range->var & ZEND_LIVE_MASK;
+ uint32_t var_num = range->var & ~ZEND_LIVE_MASK;
+ zval *var = EX_VAR(var_num);
+ if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) {
+ ZVAL_COPY_VALUE(gc_buffer++, var);
+ }
+ }
+ }
+ }
+
if (generator->node.children == 0) {
zend_generator *root = generator->node.ptr.root;
while (root != generator) {