mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Merge branch 'PHP-8.2'
* PHP-8.2: [ci skip] NEWS [ci skip] NEWS [ci skip] NEWS Fix generator memory leaks when interrupted during argument evaluation (#9756)
This commit is contained in:
commit
02ed12240e
14 changed files with 536 additions and 2 deletions
33
Zend/tests/generators/gh9750-001.phpt
Normal file
33
Zend/tests/generators/gh9750-001.phpt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 001 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
f($gen, yield);
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen(new C());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
33
Zend/tests/generators/gh9750-002.phpt
Normal file
33
Zend/tests/generators/gh9750-002.phpt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 002 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
f($gen, f(yield));
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen(new C());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
33
Zend/tests/generators/gh9750-003.phpt
Normal file
33
Zend/tests/generators/gh9750-003.phpt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 003 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
f(f($gen, yield));
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen(new C());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
33
Zend/tests/generators/gh9750-004.phpt
Normal file
33
Zend/tests/generators/gh9750-004.phpt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 004 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
f(new stdClass, $gen, yield);
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen(new C());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
34
Zend/tests/generators/gh9750-005.phpt
Normal file
34
Zend/tests/generators/gh9750-005.phpt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 002 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f(...$x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
f(b: $gen, c: yield);
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen(new C());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
$c = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
33
Zend/tests/generators/gh9750-006.phpt
Normal file
33
Zend/tests/generators/gh9750-006.phpt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 006 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f(...$x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
f(a: $gen, b: f(c: yield));
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen(new C());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
33
Zend/tests/generators/gh9750-007.phpt
Normal file
33
Zend/tests/generators/gh9750-007.phpt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 007 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f(...$x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
f(f(a: $gen, b: yield));
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen(new C());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
40
Zend/tests/generators/gh9750-008.phpt
Normal file
40
Zend/tests/generators/gh9750-008.phpt
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 008 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (version_compare(PHP_VERSION, '8.1', '<')) { die('skip Broken on PHP < 8.1'); }
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class D {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
new D($gen, yield);
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen(new C());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
37
Zend/tests/generators/gh9750-009.phpt
Normal file
37
Zend/tests/generators/gh9750-009.phpt
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 009 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
public function __construct(public mixed $x) {
|
||||||
|
}
|
||||||
|
public function __invoke() {
|
||||||
|
}
|
||||||
|
public function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function () use (&$gen) {
|
||||||
|
(new C($gen))(yield);
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen();
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
33
Zend/tests/generators/gh9750-010.phpt
Normal file
33
Zend/tests/generators/gh9750-010.phpt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 010 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
$gen->valid(yield);
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen(new C());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
38
Zend/tests/generators/gh9750-011.phpt
Normal file
38
Zend/tests/generators/gh9750-011.phpt
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-9750 011 (Generator memory leak when interrupted during argument evaluation)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
function getClosure() {
|
||||||
|
return function () {
|
||||||
|
return $this;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function __destruct() {
|
||||||
|
echo __METHOD__, "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = function ($c) use (&$gen) {
|
||||||
|
$c($gen, yield);
|
||||||
|
};
|
||||||
|
|
||||||
|
$gen = $gen((new C())->getClosure());
|
||||||
|
|
||||||
|
foreach ($gen as $value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gen = null;
|
||||||
|
|
||||||
|
gc_collect_cycles();
|
||||||
|
|
||||||
|
?>
|
||||||
|
==DONE==
|
||||||
|
--EXPECT--
|
||||||
|
C::__destruct
|
||||||
|
==DONE==
|
|
@ -4104,6 +4104,136 @@ static zend_always_inline zend_generator *zend_get_running_generator(EXECUTE_DAT
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_execute_data *call, uint32_t op_num, zend_get_gc_buffer *buf) /* {{{ */
|
||||||
|
{
|
||||||
|
zend_op *opline = EX(func)->op_array.opcodes + op_num;
|
||||||
|
int level;
|
||||||
|
int do_exit;
|
||||||
|
uint32_t num_args;
|
||||||
|
|
||||||
|
if (UNEXPECTED(opline->opcode == ZEND_INIT_FCALL ||
|
||||||
|
opline->opcode == ZEND_INIT_FCALL_BY_NAME ||
|
||||||
|
opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME ||
|
||||||
|
opline->opcode == ZEND_INIT_DYNAMIC_CALL ||
|
||||||
|
opline->opcode == ZEND_INIT_USER_CALL ||
|
||||||
|
opline->opcode == ZEND_INIT_METHOD_CALL ||
|
||||||
|
opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
|
||||||
|
opline->opcode == ZEND_NEW)) {
|
||||||
|
ZEND_ASSERT(op_num);
|
||||||
|
opline--;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* find the number of actually passed arguments */
|
||||||
|
level = 0;
|
||||||
|
do_exit = 0;
|
||||||
|
num_args = ZEND_CALL_NUM_ARGS(call);
|
||||||
|
do {
|
||||||
|
switch (opline->opcode) {
|
||||||
|
case ZEND_DO_FCALL:
|
||||||
|
case ZEND_DO_ICALL:
|
||||||
|
case ZEND_DO_UCALL:
|
||||||
|
case ZEND_DO_FCALL_BY_NAME:
|
||||||
|
level++;
|
||||||
|
break;
|
||||||
|
case ZEND_INIT_FCALL:
|
||||||
|
case ZEND_INIT_FCALL_BY_NAME:
|
||||||
|
case ZEND_INIT_NS_FCALL_BY_NAME:
|
||||||
|
case ZEND_INIT_DYNAMIC_CALL:
|
||||||
|
case ZEND_INIT_USER_CALL:
|
||||||
|
case ZEND_INIT_METHOD_CALL:
|
||||||
|
case ZEND_INIT_STATIC_METHOD_CALL:
|
||||||
|
case ZEND_NEW:
|
||||||
|
if (level == 0) {
|
||||||
|
num_args = 0;
|
||||||
|
do_exit = 1;
|
||||||
|
}
|
||||||
|
level--;
|
||||||
|
break;
|
||||||
|
case ZEND_SEND_VAL:
|
||||||
|
case ZEND_SEND_VAL_EX:
|
||||||
|
case ZEND_SEND_VAR:
|
||||||
|
case ZEND_SEND_VAR_EX:
|
||||||
|
case ZEND_SEND_FUNC_ARG:
|
||||||
|
case ZEND_SEND_REF:
|
||||||
|
case ZEND_SEND_VAR_NO_REF:
|
||||||
|
case ZEND_SEND_VAR_NO_REF_EX:
|
||||||
|
case ZEND_SEND_USER:
|
||||||
|
if (level == 0) {
|
||||||
|
/* For named args, the number of arguments is up to date. */
|
||||||
|
if (opline->op2_type != IS_CONST) {
|
||||||
|
num_args = opline->op2.num;
|
||||||
|
}
|
||||||
|
do_exit = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZEND_SEND_ARRAY:
|
||||||
|
case ZEND_SEND_UNPACK:
|
||||||
|
case ZEND_CHECK_UNDEF_ARGS:
|
||||||
|
if (level == 0) {
|
||||||
|
do_exit = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!do_exit) {
|
||||||
|
opline--;
|
||||||
|
}
|
||||||
|
} while (!do_exit);
|
||||||
|
if (call->prev_execute_data) {
|
||||||
|
/* skip current call region */
|
||||||
|
level = 0;
|
||||||
|
do_exit = 0;
|
||||||
|
do {
|
||||||
|
switch (opline->opcode) {
|
||||||
|
case ZEND_DO_FCALL:
|
||||||
|
case ZEND_DO_ICALL:
|
||||||
|
case ZEND_DO_UCALL:
|
||||||
|
case ZEND_DO_FCALL_BY_NAME:
|
||||||
|
level++;
|
||||||
|
break;
|
||||||
|
case ZEND_INIT_FCALL:
|
||||||
|
case ZEND_INIT_FCALL_BY_NAME:
|
||||||
|
case ZEND_INIT_NS_FCALL_BY_NAME:
|
||||||
|
case ZEND_INIT_DYNAMIC_CALL:
|
||||||
|
case ZEND_INIT_USER_CALL:
|
||||||
|
case ZEND_INIT_METHOD_CALL:
|
||||||
|
case ZEND_INIT_STATIC_METHOD_CALL:
|
||||||
|
case ZEND_NEW:
|
||||||
|
if (level == 0) {
|
||||||
|
do_exit = 1;
|
||||||
|
}
|
||||||
|
level--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
opline--;
|
||||||
|
} while (!do_exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EXPECTED(num_args > 0)) {
|
||||||
|
zval *p = ZEND_CALL_ARG(call, 1);
|
||||||
|
do {
|
||||||
|
zend_get_gc_buffer_add_zval(buf, p);
|
||||||
|
p++;
|
||||||
|
} while (--num_args);
|
||||||
|
}
|
||||||
|
if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
|
||||||
|
zend_get_gc_buffer_add_obj(buf, Z_OBJ(call->This));
|
||||||
|
}
|
||||||
|
if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
|
||||||
|
zval *val;
|
||||||
|
ZEND_HASH_FOREACH_VAL(call->extra_named_params, val) {
|
||||||
|
zend_get_gc_buffer_add_zval(buf, val);
|
||||||
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
}
|
||||||
|
if (call->func->common.fn_flags & ZEND_ACC_CLOSURE) {
|
||||||
|
zend_get_gc_buffer_add_obj(buf, ZEND_CLOSURE_OBJECT(call->func));
|
||||||
|
}
|
||||||
|
|
||||||
|
call = call->prev_execute_data;
|
||||||
|
} while (call);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t op_num) /* {{{ */
|
static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t op_num) /* {{{ */
|
||||||
{
|
{
|
||||||
if (UNEXPECTED(EX(call))) {
|
if (UNEXPECTED(EX(call))) {
|
||||||
|
|
|
@ -384,6 +384,7 @@ ZEND_API zval *zend_get_zval_ptr(const zend_op *opline, int op_type, const znode
|
||||||
|
|
||||||
ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table);
|
ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table);
|
||||||
ZEND_API void ZEND_FASTCALL zend_free_compiled_variables(zend_execute_data *execute_data);
|
ZEND_API void ZEND_FASTCALL zend_free_compiled_variables(zend_execute_data *execute_data);
|
||||||
|
ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_execute_data *call, uint32_t op_num, zend_get_gc_buffer *buf);
|
||||||
ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num);
|
ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num);
|
||||||
|
|
||||||
zval * ZEND_FASTCALL zend_handle_named_arg(
|
zval * ZEND_FASTCALL zend_handle_named_arg(
|
||||||
|
|
|
@ -95,6 +95,20 @@ ZEND_API zend_execute_data* zend_generator_freeze_call_stack(zend_execute_data *
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
static zend_execute_data* zend_generator_revert_call_stack(zend_execute_data *call)
|
||||||
|
{
|
||||||
|
zend_execute_data *prev = NULL;
|
||||||
|
|
||||||
|
do {
|
||||||
|
zend_execute_data *next = call->prev_execute_data;
|
||||||
|
call->prev_execute_data = prev;
|
||||||
|
prev = call;
|
||||||
|
call = next;
|
||||||
|
} while (call);
|
||||||
|
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
static void zend_generator_cleanup_unfinished_execution(
|
static void zend_generator_cleanup_unfinished_execution(
|
||||||
zend_generator *generator, zend_execute_data *execute_data, uint32_t catch_op_num) /* {{{ */
|
zend_generator *generator, zend_execute_data *execute_data, uint32_t catch_op_num) /* {{{ */
|
||||||
{
|
{
|
||||||
|
@ -373,6 +387,15 @@ static HashTable *zend_generator_get_gc(zend_object *object, zval **table, int *
|
||||||
zend_get_gc_buffer_add_zval(gc_buffer, &extra_named_params);
|
zend_get_gc_buffer_add_zval(gc_buffer, &extra_named_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UNEXPECTED(generator->frozen_call_stack)) {
|
||||||
|
/* The frozen stack is linked in reverse order */
|
||||||
|
zend_execute_data *call = zend_generator_revert_call_stack(generator->frozen_call_stack);
|
||||||
|
/* -1 required because we want the last run opcode, not the next to-be-run one. */
|
||||||
|
uint32_t op_num = execute_data->opline - op_array->opcodes - 1;
|
||||||
|
zend_unfinished_calls_gc(execute_data, call, op_num, gc_buffer);
|
||||||
|
zend_generator_revert_call_stack(call);
|
||||||
|
}
|
||||||
|
|
||||||
if (execute_data->opline != op_array->opcodes) {
|
if (execute_data->opline != op_array->opcodes) {
|
||||||
uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
|
uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
|
||||||
for (i = 0; i < op_array->last_live_range; i++) {
|
for (i = 0; i < op_array->last_live_range; i++) {
|
||||||
|
@ -603,7 +626,7 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator
|
||||||
static zend_result zend_generator_get_next_delegated_value(zend_generator *generator) /* {{{ */
|
static zend_result zend_generator_get_next_delegated_value(zend_generator *generator) /* {{{ */
|
||||||
{
|
{
|
||||||
--generator->execute_data->opline;
|
--generator->execute_data->opline;
|
||||||
|
|
||||||
zval *value;
|
zval *value;
|
||||||
if (Z_TYPE(generator->values) == IS_ARRAY) {
|
if (Z_TYPE(generator->values) == IS_ARRAY) {
|
||||||
HashTable *ht = Z_ARR(generator->values);
|
HashTable *ht = Z_ARR(generator->values);
|
||||||
|
@ -684,7 +707,7 @@ static zend_result zend_generator_get_next_delegated_value(zend_generator *gener
|
||||||
ZVAL_LONG(&generator->key, iter->index);
|
ZVAL_LONG(&generator->key, iter->index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++generator->execute_data->opline;
|
++generator->execute_data->opline;
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue