mirror of
https://github.com/php/php-src.git
synced 2024-11-27 11:53:33 +08:00
Fixed bug #78502
We need to make sure that the function is fully compiled before we calculate the stack size. There already was a check for directly recursive calls, but the same issue exists with indirectly recursive calls. I'm using DONE_PASS_TWO as the indication that the function is fully compiled.
This commit is contained in:
parent
df35d5cc21
commit
e81751ceac
31
Zend/tests/bug78502.phpt
Normal file
31
Zend/tests/bug78502.phpt
Normal file
@ -0,0 +1,31 @@
|
||||
--TEST--
|
||||
Bug #78502: Incorrect stack size calculation for indirectly recursive function call
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$tree = [
|
||||
'name' => 'a',
|
||||
'quant' => 1,
|
||||
'children' => [
|
||||
['name' => 'b', 'quant' => 1],
|
||||
['name' => 'c', 'quant' => 1, 'children' => [
|
||||
['name' => 'd', 'quant' => 1],
|
||||
]],
|
||||
],
|
||||
];
|
||||
|
||||
function tree_map($tree, $recursive_attr, closure $callback){
|
||||
if(isset($tree[$recursive_attr])){
|
||||
$tree[$recursive_attr] = array_map(function($c) use($recursive_attr, $callback){
|
||||
return tree_map($c, $recursive_attr, $callback);
|
||||
}, $tree[$recursive_attr]);
|
||||
}
|
||||
return $callback($tree);
|
||||
}
|
||||
|
||||
tree_map($tree, 'children', function ($node) {});
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECT--
|
||||
===DONE===
|
@ -3321,6 +3321,12 @@ int zend_compile_func_ord(znode *result, zend_ast_list *args) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* We can only calculate the stack size for functions that have been fully compiled, otherwise
|
||||
* additional CV or TMP slots may still be added. This prevents the use of INIT_FCALL for
|
||||
* directly or indirectly recursive function calls. */
|
||||
static zend_bool fbc_is_finalized(zend_function *fbc) {
|
||||
return !ZEND_USER_CODE(fbc->type) || (fbc->common.fn_flags & ZEND_ACC_DONE_PASS_TWO);
|
||||
}
|
||||
|
||||
static int zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t num_args) /* {{{ */
|
||||
{
|
||||
@ -3336,9 +3342,7 @@ static int zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t
|
||||
lcname = zend_string_tolower(name);
|
||||
|
||||
fbc = zend_hash_find_ptr(CG(function_table), lcname);
|
||||
if (!fbc
|
||||
/* Don't use INIT_FCALL for recursive calls */
|
||||
|| (fbc == (zend_function*)CG(active_op_array))
|
||||
if (!fbc || !fbc_is_finalized(fbc)
|
||||
|| (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS))
|
||||
|| (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS))
|
||||
|| (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) && fbc->op_array.filename != CG(active_op_array)->filename)
|
||||
@ -3461,8 +3465,7 @@ static void zend_compile_assert(znode *result, zend_ast_list *args, zend_string
|
||||
|
||||
zend_emit_op(NULL, ZEND_ASSERT_CHECK, NULL, NULL);
|
||||
|
||||
/* Don't use INIT_FCALL for recursive calls */
|
||||
if (fbc && fbc != (zend_function*)CG(active_op_array)) {
|
||||
if (fbc && fbc_is_finalized(fbc)) {
|
||||
name_node.op_type = IS_CONST;
|
||||
ZVAL_STR_COPY(&name_node.u.constant, name);
|
||||
|
||||
@ -3838,9 +3841,7 @@ void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fbc
|
||||
/* Don't use INIT_FCALL for recursive calls */
|
||||
|| (fbc == (zend_function*)CG(active_op_array))
|
||||
if (!fbc || !fbc_is_finalized(fbc)
|
||||
|| (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS))
|
||||
|| (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS))
|
||||
|| (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) && fbc->op_array.filename != CG(active_op_array)->filename)
|
||||
|
Loading…
Reference in New Issue
Block a user