diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 421b059e13e59..d19d1b98dc112 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7714,7 +7714,7 @@ static zend_string *zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_string *separator = zend_empty_string; zend_string *function = filename; char *parens = ""; - + if (CG(active_op_array) && CG(active_op_array)->function_name) { if (CG(active_op_array)->fn_flags & ZEND_ACC_CLOSURE) { /* If the parent function is a closure, don't redundantly @@ -8714,6 +8714,13 @@ static void zend_compile_const_decl(zend_ast *ast) /* {{{ */ value_node.op_type = IS_CONST; zend_const_expr_to_zval(value_zv, value_ast_ptr, /* allow_dynamic */ true); + if (UNEXPECTED( + zend_string_equals_literal_ci(unqualified_name, "exit") + || zend_string_equals_literal_ci(unqualified_name, "die") + )) { + zend_throw_error(NULL, "Cannot define constant with name %s", ZSTR_VAL(unqualified_name)); + return; + } if (zend_get_special_const(ZSTR_VAL(unqualified_name), ZSTR_LEN(unqualified_name))) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare constant '%s'", ZSTR_VAL(unqualified_name)); @@ -10009,16 +10016,36 @@ static void zend_compile_const(znode *result, zend_ast *ast) /* {{{ */ bool is_fully_qualified; zend_string *orig_name = zend_ast_get_str(name_ast); - zend_string *resolved_name = zend_resolve_const_name(orig_name, name_ast->attr, &is_fully_qualified); + /* The fake "constants" exit and die must be converted to a function call for exit() */ if (UNEXPECTED( zend_string_equals_literal_ci(orig_name, "exit") || zend_string_equals_literal_ci(orig_name, "die") )) { - zend_throw_error(NULL, "Cannot define constant with name %s", ZSTR_VAL(orig_name)); + zval *fbc_zv = zend_hash_find(CG(function_table), ZSTR_KNOWN(ZEND_STR_EXIT)); + ZEND_ASSERT(fbc_zv && "exit() function should always exist"); + zend_function *fbc = Z_PTR_P(fbc_zv); + + znode name_node; + name_node.op_type = IS_CONST; + ZVAL_STR(&name_node.u.constant, ZSTR_KNOWN(ZEND_STR_EXIT)); + + opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node); + opline->result.num = zend_alloc_cache_slot(); + + /* Store offset to function from symbol table in op2.extra. */ + { + Bucket *fbc_bucket = (Bucket*)((uintptr_t)fbc_zv - XtOffsetOf(Bucket, val)); + Z_EXTRA_P(CT_CONSTANT(opline->op2)) = fbc_bucket - CG(function_table)->arData; + } + + zend_ast *args_list = zend_ast_create_list_0(ZEND_AST_ARG_LIST); + zend_compile_call_common(result, args_list, fbc, ast->lineno); return; } + zend_string *resolved_name = zend_resolve_const_name(orig_name, name_ast->attr, &is_fully_qualified); + if (zend_string_equals_literal(resolved_name, "__COMPILER_HALT_OFFSET__") || (name_ast->attr != ZEND_NAME_RELATIVE && zend_string_equals_literal(orig_name, "__COMPILER_HALT_OFFSET__"))) { zend_ast *last = CG(ast); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 93c9c64ff3a3f..facd7239c74d7 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -5017,13 +5017,6 @@ static zend_always_inline zend_result _zend_quick_get_constant( } if (!c) { - if (UNEXPECTED( - zend_string_equals_literal_ci(Z_STR_P(key), "exit") - || zend_string_equals_literal_ci(Z_STR_P(key), "die") - )) { - zend_throw_unwind_exit(); - return FAILURE; - } if (!check_defined_only) { zend_throw_error(NULL, "Undefined constant \"%s\"", Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); ZVAL_UNDEF(EX_VAR(opline->result.var)); diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 910e2eed250fe..9cb2b05fd8bf7 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -572,6 +572,7 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_ARGS, "args") \ _(ZEND_STR_UNKNOWN, "unknown") \ _(ZEND_STR_UNKNOWN_CAPITALIZED, "Unknown") \ + _(ZEND_STR_EXIT, "exit") \ _(ZEND_STR_EVAL, "eval") \ _(ZEND_STR_INCLUDE, "include") \ _(ZEND_STR_REQUIRE, "require") \