diff --git a/Zend/Optimizer/zend_cfg.c b/Zend/Optimizer/zend_cfg.c index ce7d078bb957e..07b33065a93f0 100644 --- a/Zend/Optimizer/zend_cfg.c +++ b/Zend/Optimizer/zend_cfg.c @@ -28,6 +28,8 @@ static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_bloc { zend_basic_block *blocks = cfg->blocks; + zend_check_stack_limit("Try reducing function size"); + while (1) { int i; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 33c15f00b339c..0da707122d10c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -100,25 +100,32 @@ static void zend_compile_stmt(zend_ast *ast); static void zend_compile_assign(znode *result, zend_ast *ast); #ifdef ZEND_CHECK_STACK_LIMIT -zend_never_inline static void zend_stack_limit_error(void) +zend_never_inline static void zend_stack_limit_error(const char *suggestion) { zend_error_noreturn(E_COMPILE_ERROR, - "Maximum call stack size of %zu bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached during compilation. Try splitting expression", - (size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit))); + "Maximum call stack size of %zu bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached during compilation. %s", + (size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit)), + suggestion); } -static void zend_check_stack_limit(void) +void zend_check_stack_limit(const char *suggestion) { if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { - zend_stack_limit_error(); + zend_stack_limit_error(suggestion); } } #else /* ZEND_CHECK_STACK_LIMIT */ -static void zend_check_stack_limit(void) +void zend_check_stack_limit(const char *suggestion) { + ZEND_IGNORE_VALUE(suggestion); } #endif /* ZEND_CHECK_STACK_LIMIT */ +static void zend_check_stack_limit_expression(void) +{ + zend_check_stack_limit("Try splitting expression"); +} + static void init_op(zend_op *op) { MAKE_NOP(op); @@ -10617,7 +10624,7 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */ static void zend_compile_expr(znode *result, zend_ast *ast) { - zend_check_stack_limit(); + zend_check_stack_limit_expression(); uint32_t checkpoint = zend_short_circuiting_checkpoint(); zend_compile_expr_inner(result, ast); @@ -10715,7 +10722,7 @@ static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ return; } - zend_check_stack_limit(); + zend_check_stack_limit_expression(); switch (ast->kind) { case ZEND_AST_BINARY_OP: diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 724b5b8c8a57c..e0ad6dabd9724 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -800,6 +800,8 @@ ZEND_API size_t zend_get_scanned_file_offset(void); ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, uint32_t var); +void zend_check_stack_limit(const char *suggestion); + #ifdef ZTS const char *zend_get_zendtext(void); int zend_get_zendleng(void); diff --git a/ext/opcache/tests/jit/gh14361.phpt b/ext/opcache/tests/jit/gh14361.phpt new file mode 100644 index 0000000000000..260bc58ceb4f2 --- /dev/null +++ b/ext/opcache/tests/jit/gh14361.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-14361 (Deep recursion in zend_cfg.c causes segfault instead of error) +--SKIPIF-- + +--EXTENSIONS-- +zend_test +opcache +--INI-- +error_reporting=E_COMPILE_ERROR +zend.max_allowed_stack_size=128K +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_buffer_size=64M +opcache.optimization_level=0x000000a0 +--FILE-- + +--CLEAN-- + +--EXPECTF-- +Fatal error: Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached during compilation. Try reducing function size in %s on line %d