diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2018-09-28 19:17:43 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2018-09-28 19:17:53 +0200 |
commit | 7189e0b70f54b313dd4fe310d4bf3e1dfe6ec95d (patch) | |
tree | 2aee2e3ec1a5651508c953e0a39543c8dc959ca3 | |
parent | 0470d21ef3f6c61401cbde446232becdbb186efd (diff) | |
parent | 8e7dfc6ddf97db89871cc296ea68a31c72312121 (diff) | |
download | php-git-7189e0b70f54b313dd4fe310d4bf3e1dfe6ec95d.tar.gz |
Merge branch 'PHP-7.2' into PHP-7.3
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | Zend/tests/bug76946.phpt | 27 | ||||
-rw-r--r-- | Zend/zend_generators.c | 36 |
3 files changed, 64 insertions, 0 deletions
@@ -5,6 +5,7 @@ PHP NEWS - Core: . Fixed bug #76846 (Segfault in shutdown function after memory limit error). (Nikita) + . Fixed bug #76946 (Cyclic reference in generator not detected). (Nikita) 27 Sep 2018, PHP 7.3.0RC2 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 0198b3171e..1162c7653f 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -276,6 +276,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; @@ -342,6 +361,23 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* { ZVAL_OBJ(gc_buffer++, ZEND_CLOSURE_OBJECT(EX(func))); } + 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) { |