mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix bug #69989
This should cover all the basic cycles. Anything further would require scanning the call stack and live temporaries.
This commit is contained in:
1
NEWS
1
NEWS
@@ -4,6 +4,7 @@ PHP NEWS
|
||||
|
||||
- Core:
|
||||
. Fixed bug #62210 (Exceptions can leak temporary variables). (Dmitry, Bob)
|
||||
. Fixed bug #69989 (Generators don't participate in cycle GC). (Nikita)
|
||||
. Implemented the RFC `Support Class Constant Visibility`. (Sean DuBois,
|
||||
Reeze Xia, Dmitry)
|
||||
. Added void return type. (Andrea)
|
||||
|
||||
44
Zend/tests/bug69989_3.phpt
Normal file
44
Zend/tests/bug69989_3.phpt
Normal file
@@ -0,0 +1,44 @@
|
||||
--TEST--
|
||||
Generator cycle collection edge cases
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// Extra args
|
||||
function gen1() {
|
||||
yield;
|
||||
}
|
||||
$obj = new stdClass;
|
||||
$obj->gen = gen1($obj);
|
||||
|
||||
// Symtable
|
||||
function gen2() {
|
||||
$varName = 'a';
|
||||
$$varName = yield;
|
||||
yield;
|
||||
}
|
||||
$gen = gen2();
|
||||
$gen->send($gen);
|
||||
|
||||
// Symtable indirect
|
||||
function gen3() {
|
||||
$varName = 'a';
|
||||
$$varName = 42;
|
||||
$var = yield;
|
||||
yield;
|
||||
}
|
||||
$gen = gen3();
|
||||
$gen->send($gen);
|
||||
|
||||
// Yield from root
|
||||
function gen4() {
|
||||
yield from yield;
|
||||
}
|
||||
$gen = gen4();
|
||||
$gen2 = gen4($gen);
|
||||
$gen2->send([1, 2, 3]);
|
||||
$gen->send($gen2);
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECT--
|
||||
===DONE===
|
||||
@@ -201,9 +201,25 @@ static uint32_t calc_gc_buffer_size(zend_generator *generator) /* {{{ */
|
||||
zend_execute_data *execute_data = generator->execute_data;
|
||||
zend_op_array *op_array = &EX(func)->op_array;
|
||||
|
||||
size += op_array->last_var; /* CVs */
|
||||
/* Compiled variables */
|
||||
if (!execute_data->symbol_table) {
|
||||
size += op_array->last_var;
|
||||
}
|
||||
/* Extra args */
|
||||
if (EX_CALL_INFO() & ZEND_CALL_FREE_EXTRA_ARGS) {
|
||||
size += EX_NUM_ARGS() - op_array->num_args;
|
||||
}
|
||||
size += Z_OBJ(execute_data->This) != NULL; /* $this */
|
||||
size += (EX_CALL_INFO() & ZEND_CALL_CLOSURE) != 0; /* Closure object */
|
||||
|
||||
/* Yield from root references */
|
||||
if (generator->node.children == 0) {
|
||||
zend_generator *root = generator->node.ptr.root;
|
||||
while (root != generator) {
|
||||
size++;
|
||||
root = zend_generator_get_child(&root->node, generator);
|
||||
}
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@@ -213,6 +229,7 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
|
||||
{
|
||||
zend_generator *generator = (zend_generator*) Z_OBJ_P(object);
|
||||
zend_execute_data *execute_data = generator->execute_data;
|
||||
zend_op_array *op_array;
|
||||
zval *gc_buffer;
|
||||
uint32_t gc_buffer_size;
|
||||
|
||||
@@ -224,9 +241,11 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
op_array = &EX(func)->op_array;
|
||||
gc_buffer_size = calc_gc_buffer_size(generator);
|
||||
if (!generator->gc_buffer) {
|
||||
generator->gc_buffer = safe_emalloc(sizeof(zval), gc_buffer_size, 0);
|
||||
if (generator->gc_buffer_size < gc_buffer_size) {
|
||||
generator->gc_buffer = safe_erealloc(generator->gc_buffer, sizeof(zval), gc_buffer_size, 0);
|
||||
generator->gc_buffer_size = gc_buffer_size;
|
||||
}
|
||||
|
||||
*n = gc_buffer_size;
|
||||
@@ -237,13 +256,21 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
|
||||
ZVAL_COPY_VALUE(gc_buffer++, &generator->retval);
|
||||
ZVAL_COPY_VALUE(gc_buffer++, &generator->values);
|
||||
|
||||
{
|
||||
if (!execute_data->symbol_table) {
|
||||
uint32_t i, num_cvs = EX(func)->op_array.last_var;
|
||||
for (i = 0; i < num_cvs; i++) {
|
||||
ZVAL_COPY_VALUE(gc_buffer++, EX_VAR_NUM(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (EX_CALL_INFO() & ZEND_CALL_FREE_EXTRA_ARGS) {
|
||||
zval *zv = EX_VAR_NUM(op_array->last_var + op_array->T);
|
||||
zval *end = zv + (EX_NUM_ARGS() - op_array->num_args);
|
||||
while (zv != end) {
|
||||
ZVAL_COPY_VALUE(gc_buffer++, zv++);
|
||||
}
|
||||
}
|
||||
|
||||
if (Z_OBJ(execute_data->This)) {
|
||||
ZVAL_OBJ(gc_buffer++, Z_OBJ(execute_data->This));
|
||||
}
|
||||
@@ -251,7 +278,15 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
|
||||
ZVAL_OBJ(gc_buffer++, (zend_object *) EX(func)->common.prototype);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
if (generator->node.children == 0) {
|
||||
zend_generator *root = generator->node.ptr.root;
|
||||
while (root != generator) {
|
||||
ZVAL_OBJ(gc_buffer++, &root->std);
|
||||
root = zend_generator_get_child(&root->node, generator);
|
||||
}
|
||||
}
|
||||
|
||||
return execute_data->symbol_table;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ struct _zend_generator {
|
||||
zend_uchar flags;
|
||||
|
||||
zval *gc_buffer;
|
||||
uint32_t gc_buffer_size;
|
||||
};
|
||||
|
||||
static const zend_uchar ZEND_GENERATOR_CURRENTLY_RUNNING = 0x1;
|
||||
|
||||
Reference in New Issue
Block a user