diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2018-09-28 19:14:47 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2018-09-28 19:15:19 +0200 |
commit | 83e2b9e2202da6cc25bdaac67a58022b90be88e7 (patch) | |
tree | 3ea01fc88cefcc05a28e11c6294beb4e5a517c25 | |
parent | 69c1b619c9d6a20dd5a50a058659c5c4233aea82 (diff) | |
download | php-git-83e2b9e2202da6cc25bdaac67a58022b90be88e7.tar.gz |
Fixed bug #76946
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | Zend/tests/bug76946.phpt | 27 | ||||
-rw-r--r-- | Zend/zend_generators.c | 36 |
3 files changed, 65 insertions, 0 deletions
@@ -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) { |