Skip to content

Commit 7189e0b

Browse files
committed
Merge branch 'PHP-7.2' into PHP-7.3
2 parents 0470d21 + 8e7dfc6 commit 7189e0b

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ PHP NEWS
55
- Core:
66
. Fixed bug #76846 (Segfault in shutdown function after memory limit error).
77
(Nikita)
8+
. Fixed bug #76946 (Cyclic reference in generator not detected). (Nikita)
89

910
27 Sep 2018, PHP 7.3.0RC2
1011

Zend/tests/bug76946.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Bug #76946: Cyclic reference in generator not detected
3+
--FILE--
4+
<?php
5+
6+
function gen() {
7+
$gen = yield;
8+
foreach ([1, $gen] as $v) {
9+
yield $v;
10+
}
11+
}
12+
13+
function gen2() {
14+
$gen = yield;
15+
$gen + yield;
16+
}
17+
18+
$gen = gen();
19+
$gen->send($gen);
20+
21+
$gen2 = gen2();
22+
$gen2->send($gen2);
23+
24+
?>
25+
===DONE===
26+
--EXPECT--
27+
===DONE===

Zend/zend_generators.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,25 @@ static uint32_t calc_gc_buffer_size(zend_generator *generator) /* {{{ */
276276
size += Z_TYPE(execute_data->This) == IS_OBJECT; /* $this */
277277
size += (EX_CALL_INFO() & ZEND_CALL_CLOSURE) != 0; /* Closure object */
278278

279+
/* Live vars */
280+
if (execute_data->opline != op_array->opcodes) {
281+
/* -1 required because we want the last run opcode, not the next to-be-run one. */
282+
uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
283+
for (i = 0; i < op_array->last_live_range; i++) {
284+
const zend_live_range *range = &op_array->live_range[i];
285+
if (range->start > op_num) {
286+
/* Further ranges will not be relevant... */
287+
break;
288+
} else if (op_num < range->end) {
289+
/* LIVE_ROPE and LIVE_SILENCE not relevant for GC */
290+
uint32_t kind = range->var & ZEND_LIVE_MASK;
291+
if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) {
292+
size++;
293+
}
294+
}
295+
}
296+
}
297+
279298
/* Yield from root references */
280299
if (generator->node.children == 0) {
281300
zend_generator *root = generator->node.ptr.root;
@@ -342,6 +361,23 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
342361
ZVAL_OBJ(gc_buffer++, ZEND_CLOSURE_OBJECT(EX(func)));
343362
}
344363

364+
if (execute_data->opline != op_array->opcodes) {
365+
uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
366+
for (i = 0; i < op_array->last_live_range; i++) {
367+
const zend_live_range *range = &op_array->live_range[i];
368+
if (range->start > op_num) {
369+
break;
370+
} else if (op_num < range->end) {
371+
uint32_t kind = range->var & ZEND_LIVE_MASK;
372+
uint32_t var_num = range->var & ~ZEND_LIVE_MASK;
373+
zval *var = EX_VAR(var_num);
374+
if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) {
375+
ZVAL_COPY_VALUE(gc_buffer++, var);
376+
}
377+
}
378+
}
379+
}
380+
345381
if (generator->node.children == 0) {
346382
zend_generator *root = generator->node.ptr.root;
347383
while (root != generator) {

0 commit comments

Comments
 (0)