mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fix GH-8841: php-cli core dump calling a badly formed function
It's actually not php-cli specific, nor SAPI specific. We should delay the registration of the function into the function table until after the compilation was successful, otherwise the function is mistakingly registered and a NULL dereference will happen when trying to call it. I based my test of Nikita's test, so credits to him for the test: https://github.com/php/php-src/pull/8933#issuecomment-1259881008 Closes GH-10989.
This commit is contained in:
parent
66ce205718
commit
cf9b030a57
3 changed files with 47 additions and 13 deletions
2
NEWS
2
NEWS
|
@ -4,6 +4,8 @@ PHP NEWS
|
||||||
|
|
||||||
- Core:
|
- Core:
|
||||||
. Fix inconsistent float negation in constant expressions. (ilutov)
|
. Fix inconsistent float negation in constant expressions. (ilutov)
|
||||||
|
. Fixed bug GH-8841 (php-cli core dump calling a badly formed function).
|
||||||
|
(nielsdos)
|
||||||
|
|
||||||
- DOM:
|
- DOM:
|
||||||
. Fixed bug #80602 (Segfault when using DOMChildNode::before()).
|
. Fixed bug #80602 (Segfault when using DOMChildNode::before()).
|
||||||
|
|
30
Zend/tests/gh8841.phpt
Normal file
30
Zend/tests/gh8841.phpt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
--TEST--
|
||||||
|
GH-8841 (php-cli core dump calling a badly formed function)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
register_shutdown_function(function() {
|
||||||
|
echo "Before calling g()\n";
|
||||||
|
g(1);
|
||||||
|
echo "After calling g()\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
register_shutdown_function(function() {
|
||||||
|
echo "Before calling f()\n";
|
||||||
|
f(1);
|
||||||
|
echo "After calling f()\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
eval('function g($x): int { return $x; }');
|
||||||
|
eval('function f($x): void { return $x; }');
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: A void function must not return a value in %s on line %d
|
||||||
|
Before calling g()
|
||||||
|
After calling g()
|
||||||
|
Before calling f()
|
||||||
|
|
||||||
|
Fatal error: Uncaught Error: Call to undefined function f() in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 [internal function]: {closure}()
|
||||||
|
#1 {main}
|
||||||
|
thrown in %s on line %d
|
|
@ -7126,7 +7126,7 @@ static uint32_t zend_add_dynamic_func_def(zend_op_array *def) {
|
||||||
return def_offset;
|
return def_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, bool toplevel) /* {{{ */
|
static zend_string *zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, bool toplevel) /* {{{ */
|
||||||
{
|
{
|
||||||
zend_string *unqualified_name, *name, *lcname;
|
zend_string *unqualified_name, *name, *lcname;
|
||||||
zend_op *opline;
|
zend_op *opline;
|
||||||
|
@ -7157,11 +7157,7 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
|
||||||
|
|
||||||
zend_register_seen_symbol(lcname, ZEND_SYMBOL_FUNCTION);
|
zend_register_seen_symbol(lcname, ZEND_SYMBOL_FUNCTION);
|
||||||
if (toplevel) {
|
if (toplevel) {
|
||||||
if (UNEXPECTED(zend_hash_add_ptr(CG(function_table), lcname, op_array) == NULL)) {
|
return lcname;
|
||||||
do_bind_function_error(lcname, op_array, 1);
|
|
||||||
}
|
|
||||||
zend_string_release_ex(lcname, 0);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t func_ref = zend_add_dynamic_func_def(op_array);
|
uint32_t func_ref = zend_add_dynamic_func_def(op_array);
|
||||||
|
@ -7175,7 +7171,8 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
|
||||||
LITERAL_STR(opline->op1, zend_string_copy(lcname));
|
LITERAL_STR(opline->op1, zend_string_copy(lcname));
|
||||||
opline->op2.num = func_ref;
|
opline->op2.num = func_ref;
|
||||||
}
|
}
|
||||||
zend_string_release_ex(lcname, 0);
|
|
||||||
|
return lcname;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -7187,7 +7184,7 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
|
||||||
zend_ast *stmt_ast = decl->child[2];
|
zend_ast *stmt_ast = decl->child[2];
|
||||||
zend_ast *return_type_ast = decl->child[3];
|
zend_ast *return_type_ast = decl->child[3];
|
||||||
bool is_method = decl->kind == ZEND_AST_METHOD;
|
bool is_method = decl->kind == ZEND_AST_METHOD;
|
||||||
zend_string *method_lcname = NULL;
|
zend_string *lcname;
|
||||||
|
|
||||||
zend_class_entry *orig_class_entry = CG(active_class_entry);
|
zend_class_entry *orig_class_entry = CG(active_class_entry);
|
||||||
zend_op_array *orig_op_array = CG(active_op_array);
|
zend_op_array *orig_op_array = CG(active_op_array);
|
||||||
|
@ -7219,9 +7216,9 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
|
||||||
|
|
||||||
if (is_method) {
|
if (is_method) {
|
||||||
bool has_body = stmt_ast != NULL;
|
bool has_body = stmt_ast != NULL;
|
||||||
method_lcname = zend_begin_method_decl(op_array, decl->name, has_body);
|
lcname = zend_begin_method_decl(op_array, decl->name, has_body);
|
||||||
} else {
|
} else {
|
||||||
zend_begin_func_decl(result, op_array, decl, toplevel);
|
lcname = zend_begin_func_decl(result, op_array, decl, toplevel);
|
||||||
if (decl->kind == ZEND_AST_ARROW_FUNC) {
|
if (decl->kind == ZEND_AST_ARROW_FUNC) {
|
||||||
find_implicit_binds(&info, params_ast, stmt_ast);
|
find_implicit_binds(&info, params_ast, stmt_ast);
|
||||||
compile_implicit_lexical_binds(&info, result, op_array);
|
compile_implicit_lexical_binds(&info, result, op_array);
|
||||||
|
@ -7264,7 +7261,7 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
zend_compile_params(params_ast, return_type_ast,
|
zend_compile_params(params_ast, return_type_ast,
|
||||||
is_method && zend_string_equals_literal(method_lcname, ZEND_TOSTRING_FUNC_NAME) ? IS_STRING : 0);
|
is_method && zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME) ? IS_STRING : 0);
|
||||||
if (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
|
if (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
|
||||||
zend_mark_function_as_generator();
|
zend_mark_function_as_generator();
|
||||||
zend_emit_op(NULL, ZEND_GENERATOR_CREATE, NULL, NULL);
|
zend_emit_op(NULL, ZEND_GENERATOR_CREATE, NULL, NULL);
|
||||||
|
@ -7280,9 +7277,14 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
|
||||||
if (is_method) {
|
if (is_method) {
|
||||||
CG(zend_lineno) = decl->start_lineno;
|
CG(zend_lineno) = decl->start_lineno;
|
||||||
zend_check_magic_method_implementation(
|
zend_check_magic_method_implementation(
|
||||||
CG(active_class_entry), (zend_function *) op_array, method_lcname, E_COMPILE_ERROR);
|
CG(active_class_entry), (zend_function *) op_array, lcname, E_COMPILE_ERROR);
|
||||||
zend_string_release_ex(method_lcname, 0);
|
} else if (toplevel) {
|
||||||
|
/* Only register the function after a successful compile */
|
||||||
|
if (UNEXPECTED(zend_hash_add_ptr(CG(function_table), lcname, op_array) == NULL)) {
|
||||||
|
do_bind_function_error(lcname, op_array, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
zend_string_release_ex(lcname, 0);
|
||||||
|
|
||||||
/* put the implicit return on the really last line */
|
/* put the implicit return on the really last line */
|
||||||
CG(zend_lineno) = decl->end_lineno;
|
CG(zend_lineno) = decl->end_lineno;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue