From 084e409694202af1562d3c5f91caeb88534afe2c Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 22 Oct 2025 01:03:43 +0200 Subject: [PATCH] Remove zend_exception_save() and zend_exception_restore() These are leftovers from the pre-PHP-7.0 era. This also implicitly solves GH-20564 by not clearing exceptions before entering the autoloader. Closes GH-20256 Fixes GH-20564 --- NEWS | 1 + UPGRADING.INTERNALS | 2 ++ Zend/tests/gh20564.phpt | 24 ++++++++++++++++++++++++ Zend/zend.c | 1 - Zend/zend_exceptions.c | 29 ----------------------------- Zend/zend_exceptions.h | 2 -- Zend/zend_execute.c | 1 + Zend/zend_execute_API.c | 3 --- Zend/zend_globals.h | 2 +- Zend/zend_language_scanner.l | 5 +++-- Zend/zend_vm_def.h | 3 --- Zend/zend_vm_execute.h | 14 -------------- ext/opcache/ZendAccelerator.c | 1 - sapi/fuzzer/fuzzer-execute-common.h | 2 -- sapi/phpdbg/phpdbg_prompt.c | 5 ----- 15 files changed, 32 insertions(+), 63 deletions(-) create mode 100644 Zend/tests/gh20564.phpt diff --git a/NEWS b/NEWS index f42cfc4e5ee..74816c94a29 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ PHP NEWS . Added `clamp()`. (kylekatarnls, thinkverse) . Fix OSS-Fuzz #429429090 (Failed assertion on unset() with uninitialized container). (ilutov) + . Fixed GH-20564 (Don't call autoloaders with pending exception). (ilutov) - Date: . Update timelib to 2022.16. (Derick) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 748549e085b..2132006540c 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -54,6 +54,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES ZEND_ACC_USER_ARG_INFO flag was set. . Added zend_ast_call_get_args() to fetch the argument node from any call node. + . The zend_exception_save() and zend_exception_restore() functions were + removed. ======================== 2. Build system changes diff --git a/Zend/tests/gh20564.phpt b/Zend/tests/gh20564.phpt new file mode 100644 index 00000000000..53311d952de --- /dev/null +++ b/Zend/tests/gh20564.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-20564: Don't call autoloaders with pending exception +--CREDITS-- +Viet Hoang Luu (@vi3tL0u1s) +--FILE-- +test(); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +array_map(): Argument #1 ($callback) must be a valid callback or null, class "B" not found diff --git a/Zend/zend.c b/Zend/zend.c index 6b0ffb73ad7..d2be69a7576 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1978,7 +1978,6 @@ ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handl zend_result ret = SUCCESS; if (op_array) { zend_execute(op_array, retval); - zend_exception_restore(); if (UNEXPECTED(EG(exception))) { if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { zend_user_exception_handler(); diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 191d8f7fe6a..52e3ab00925 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -145,31 +145,6 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo } /* }}} */ -void zend_exception_save(void) /* {{{ */ -{ - if (EG(prev_exception)) { - zend_exception_set_previous(EG(exception), EG(prev_exception)); - } - if (EG(exception)) { - EG(prev_exception) = EG(exception); - } - EG(exception) = NULL; -} -/* }}} */ - -void zend_exception_restore(void) /* {{{ */ -{ - if (EG(prev_exception)) { - if (EG(exception)) { - zend_exception_set_previous(EG(exception), EG(prev_exception)); - } else { - EG(exception) = EG(prev_exception); - } - EG(prev_exception) = NULL; - } -} -/* }}} */ - static zend_always_inline bool is_handle_exception_set(void) { zend_execute_data *execute_data = EG(current_execute_data); return !execute_data @@ -241,10 +216,6 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* ZEND_API void zend_clear_exception(void) /* {{{ */ { zend_object *exception; - if (EG(prev_exception)) { - OBJ_RELEASE(EG(prev_exception)); - EG(prev_exception) = NULL; - } if (!EG(exception)) { return; } diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 24d9f4efd80..e5a6be2f32f 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -41,8 +41,6 @@ extern ZEND_API zend_class_entry *zend_ce_unhandled_match_error; extern ZEND_API zend_class_entry *zend_ce_request_parse_body_exception; ZEND_API void zend_exception_set_previous(zend_object *exception, zend_object *add_previous); -ZEND_API void zend_exception_save(void); -ZEND_API void zend_exception_restore(void); ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index a4460286bf6..e95931276ef 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1315,6 +1315,7 @@ ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_exe if ((fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && !zend_verify_internal_arg_types(fbc, call)) { + zend_clear_exception(); return 1; } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index e134d3d496b..69337e27fd5 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -176,7 +176,6 @@ void init_executor(void) /* {{{ */ ZEND_ATOMIC_BOOL_INIT(&EG(timed_out), false); EG(exception) = NULL; - EG(prev_exception) = NULL; EG(fake_scope) = NULL; EG(trampoline).common.function_name = NULL; @@ -1268,9 +1267,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * zend_long previous_lineno = EG(lineno_override); EG(filename_override) = NULL; EG(lineno_override) = -1; - zend_exception_save(); ce = zend_autoload(autoload_name, lc_name); - zend_exception_restore(); EG(filename_override) = previous_filename; EG(lineno_override) = previous_lineno; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index ef81ae5faaf..f09b81acb31 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -255,7 +255,7 @@ struct _zend_executor_globals { zend_objects_store objects_store; zend_lazy_objects_store lazy_objects_store; - zend_object *exception, *prev_exception; + zend_object *exception; const zend_op *opline_before_exception; zend_op exception_op[3]; diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 1e26ddbd991..5a8a78cc3bd 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -2765,7 +2765,8 @@ skip_escape_conversion: zend_ptr_stack_reverse_apply(¤t_state.heredoc_label_stack, copy_heredoc_label_stack); - zend_exception_save(); + zend_object *prev_exception = EG(exception); + EG(exception) = NULL; while (heredoc_nesting_level) { zval zv; int retval; @@ -2794,7 +2795,7 @@ skip_escape_conversion: heredoc_nesting_level = 0; } } - zend_exception_restore(); + EG(exception) = prev_exception; if ( (first_token == T_VARIABLE diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 86de5992a8f..9840bf28040 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4797,10 +4797,8 @@ ZEND_VM_COLD_CONST_HANDLER(108, ZEND_THROW, CONST|TMPVAR|CV, ANY) } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); FREE_OP1(); HANDLE_EXCEPTION(); } @@ -4813,7 +4811,6 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, JMP_ADDR, LAST_CATCH|CACHE_SLOT) SAVE_OPLINE(); /* Check whether an exception has been thrown, if not, jump over code */ - zend_exception_restore(); if (EG(exception) == NULL) { ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 0); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 62d645c1510..7aa0296aa42 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5125,10 +5125,8 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); HANDLE_EXCEPTION(); @@ -5142,7 +5140,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_CATCH_SPEC_CO SAVE_OPLINE(); /* Check whether an exception has been thrown, if not, jump over code */ - zend_exception_restore(); if (EG(exception) == NULL) { ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 0); } @@ -15720,10 +15717,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_THROW_SPEC_TM } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); HANDLE_EXCEPTION(); } @@ -41901,10 +41896,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_THROW_SPEC_CV } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); HANDLE_EXCEPTION(); @@ -60784,10 +60777,8 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_THROW } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); HANDLE_EXCEPTION(); @@ -60801,7 +60792,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_CATCH_SPEC_CONST_T SAVE_OPLINE(); /* Check whether an exception has been thrown, if not, jump over code */ - zend_exception_restore(); if (EG(exception) == NULL) { ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 0); } @@ -71277,10 +71267,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_THROW_SPEC_TMPVAR_ } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); HANDLE_EXCEPTION(); } @@ -97358,10 +97346,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_THROW_SPEC_CV_TAIL } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); HANDLE_EXCEPTION(); diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 7acb14b778f..f4134212bc4 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4663,7 +4663,6 @@ static zend_result accel_preload(const char *config, bool in_child) zend_destroy_file_handle(&file_handle); if (op_array) { zend_execute(op_array, NULL); - zend_exception_restore(); if (UNEXPECTED(EG(exception))) { if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { zend_user_exception_handler(); diff --git a/sapi/fuzzer/fuzzer-execute-common.h b/sapi/fuzzer/fuzzer-execute-common.h index 338c771e551..ef2ff4ee79b 100644 --- a/sapi/fuzzer/fuzzer-execute-common.h +++ b/sapi/fuzzer/fuzzer-execute-common.h @@ -134,7 +134,6 @@ ZEND_ATTRIBUTE_UNUSED static void create_file(void) { ZEND_ATTRIBUTE_UNUSED static void opcache_invalidate(void) { steps_left = MAX_STEPS; - zend_exception_save(); zval retval, args[2]; zend_function *fn = zend_hash_str_find_ptr(CG(function_table), ZEND_STRL("opcache_invalidate")); ZEND_ASSERT(fn != NULL); @@ -145,5 +144,4 @@ ZEND_ATTRIBUTE_UNUSED static void opcache_invalidate(void) { ZEND_ASSERT(Z_TYPE(retval) == IS_TRUE); zval_ptr_dtor(&args[0]); zval_ptr_dtor(&retval); - zend_exception_restore(); } diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 7215888cb25..9566c1abd4e 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -716,10 +716,6 @@ static inline void phpdbg_handle_exception(void) /* {{{ */ phpdbg_writeln("%s", ZSTR_VAL(msg)); zend_string_release(msg); - if (EG(prev_exception)) { - OBJ_RELEASE(EG(prev_exception)); - EG(prev_exception) = 0; - } OBJ_RELEASE(ex); EG(opline_before_exception) = NULL; @@ -876,7 +872,6 @@ free_cmd: } zend_end_try(); if (restore) { - zend_exception_restore(); zend_try { zend_try_exception_handler(); PHPDBG_G(in_execution) = 1;