diff --git a/Zend/tests/bug63206.phpt b/Zend/tests/bug63206.phpt index 6aba55eca1ba..b962ad1b4d18 100644 --- a/Zend/tests/bug63206.phpt +++ b/Zend/tests/bug63206.phpt @@ -14,13 +14,13 @@ set_error_handler(function() { echo 'Internal handler' . PHP_EOL; }); - $triggerInternalNotice++; // warnings while handling the error should go into internal handler + trigger_error('Error', E_USER_WARNING); // warnings while handling the error should go into internal handler restore_error_handler(); }); -$triggerNotice1++; -$triggerNotice2++; +trigger_error('Error', E_USER_WARNING); +trigger_error('Error', E_USER_WARNING); ?> --EXPECT-- Second handler diff --git a/Zend/tests/bug63206_1.phpt b/Zend/tests/bug63206_1.phpt index d0542116388b..499e0d113716 100644 --- a/Zend/tests/bug63206_1.phpt +++ b/Zend/tests/bug63206_1.phpt @@ -20,7 +20,7 @@ set_error_handler(function() { restore_error_handler(); restore_error_handler(); -$triggerNotice++; +trigger_error('Error', E_USER_WARNING); ?> --EXPECT-- Second handler diff --git a/Zend/tests/gc/bug64960.phpt b/Zend/tests/gc/bug64960.phpt index d3dcc4da8c5e..713eef47869b 100644 --- a/Zend/tests/gc/bug64960.phpt +++ b/Zend/tests/gc/bug64960.phpt @@ -26,7 +26,7 @@ set_error_handler(function() }); // trigger error handler -$a['waa']; +trigger_error('Error', E_USER_WARNING); ?> --EXPECTF-- Notice: ob_end_flush(): Failed to delete and flush buffer. No buffer to delete or flush in %sbug64960.php on line 3 diff --git a/Zend/tests/get_error_handler.phpt b/Zend/tests/get_error_handler.phpt index abe0b608a4cf..5a409f90eca7 100644 --- a/Zend/tests/get_error_handler.phpt +++ b/Zend/tests/get_error_handler.phpt @@ -1,5 +1,7 @@ --TEST-- get_error_handler() +--XFAIL-- +Getting callable from FCC cannot give a correct representation for static methods (string or array) --FILE-- trampoline, 0, sizeof(zend_op_array)); executor_globals->capture_warnings_during_sccp = 0; executor_globals->user_error_handler_error_reporting = 0; - ZVAL_UNDEF(&executor_globals->user_error_handler); - ZVAL_UNDEF(&executor_globals->user_exception_handler); + executor_globals->user_error_handler = empty_fcall_info_cache; + executor_globals->user_exception_handler = empty_fcall_info_cache; ZVAL_UNDEF(&executor_globals->last_fatal_error_backtrace); executor_globals->current_execute_data = NULL; executor_globals->current_module = NULL; @@ -1443,7 +1443,6 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( { zval params[4]; zval retval; - zval orig_user_error_handler; bool in_compilation; zend_class_entry *saved_class_entry = NULL; zend_stack loop_var_stack; @@ -1451,7 +1450,6 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( int type = orig_type & E_ALL; bool orig_record_errors; zend_err_buf orig_errors_buf; - zend_result res; /* If we're executing a function during SCCP, count any warnings that may be emitted, * but don't perform any other error handling. */ @@ -1530,10 +1528,17 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( zend_observer_error_notify(type, error_filename, error_lineno, message); - /* if we don't have a user defined error handler */ - if (Z_TYPE(EG(user_error_handler)) == IS_UNDEF + /* Use default error handler if */ + if ( + /* there is no user defined error handler */ + !ZEND_FCC_INITIALIZED(EG(user_error_handler)) + /* the error handler is called recursively */ + || EG(current_executed_error_handler_stack_position) == zend_stack_count(&EG(user_error_handlers)) + /* the error handler doesn't handle the current severity */ || !(EG(user_error_handler_error_reporting) & type) - || EG(error_handling) != EH_NORMAL) { + /* the error handler was overridden by an internal extension function/method */ + || EG(error_handling) != EH_NORMAL + ) { zend_error_cb(orig_type, error_filename, error_lineno, message); } else switch (type) { case E_ERROR: @@ -1558,9 +1563,6 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( ZVAL_LONG(¶ms[3], error_lineno); - ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler)); - ZVAL_UNDEF(&EG(user_error_handler)); - /* User error handler may include() additional PHP files. * If an error was generated during compilation PHP will compile * such scripts recursively, but some CG() variables may be @@ -1581,18 +1583,23 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( orig_errors_buf = EG(errors); memset(&EG(errors), 0, sizeof(EG(errors))); - res = call_user_function(CG(function_table), NULL, &orig_user_error_handler, &retval, 4, params); + /* To prevent recursive calls of the error handler, we store the stack position of the current error handler */ + EG(current_executed_error_handler_stack_position) = zend_stack_count(&EG(user_error_handlers)); + + zend_call_known_fcc(&EG(user_error_handler), &retval, 4, params, NULL); + /* Reset stack position of the current error handler */ + EG(current_executed_error_handler_stack_position) = -1; + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[1]); EG(record_errors) = orig_record_errors; EG(errors) = orig_errors_buf; - if (res == SUCCESS) { - if (Z_TYPE(retval) != IS_UNDEF) { - if (Z_TYPE(retval) == IS_FALSE) { - zend_error_cb(orig_type, error_filename, error_lineno, message); - } - zval_ptr_dtor(&retval); + if (Z_TYPE(retval) != IS_UNDEF) { + if (Z_TYPE(retval) == IS_FALSE) { + zend_error_cb(orig_type, error_filename, error_lineno, message); } + zval_ptr_dtor(&retval); } else if (!EG(exception)) { /* The user error handler failed, use built-in error handler */ zend_error_cb(orig_type, error_filename, error_lineno, message); @@ -1605,14 +1612,6 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( CG(in_compilation) = 1; } - zval_ptr_dtor(¶ms[2]); - zval_ptr_dtor(¶ms[1]); - - if (Z_TYPE(EG(user_error_handler)) == IS_UNDEF) { - ZVAL_COPY_VALUE(&EG(user_error_handler), &orig_user_error_handler); - } else { - zval_ptr_dtor(&orig_user_error_handler); - } break; } @@ -1929,39 +1928,38 @@ ZEND_API ZEND_COLD void zend_output_debug_string(bool trigger_break, const char ZEND_API ZEND_COLD void zend_user_exception_handler(void) /* {{{ */ { - zval orig_user_exception_handler; - zval params[1], retval2; - zend_object *old_exception; - if (zend_is_unwind_exit(EG(exception))) { return; } - old_exception = EG(exception); + zend_object *old_exception = EG(exception); EG(exception) = NULL; + + zval params[1]; ZVAL_OBJ(¶ms[0], old_exception); - ZVAL_COPY_VALUE(&orig_user_exception_handler, &EG(user_exception_handler)); - zend_stack_push(&EG(user_exception_handlers), &orig_user_exception_handler); - ZVAL_UNDEF(&EG(user_exception_handler)); + zend_fcall_info_cache fcc = EG(user_exception_handler); + /* Push the current handler on the stack and set the current one to the default handler to prevent recursion */ + zend_stack_push(&EG(user_exception_handlers), &EG(user_exception_handler)); - if (call_user_function(CG(function_table), NULL, &orig_user_exception_handler, &retval2, 1, params) == SUCCESS) { - zval_ptr_dtor(&retval2); - if (EG(exception)) { - OBJ_RELEASE(EG(exception)); - EG(exception) = NULL; - } - OBJ_RELEASE(old_exception); - } else { - EG(exception) = old_exception; + int current_stack_position = zend_stack_count(&EG(user_exception_handlers)); + + EG(user_exception_handler) = empty_fcall_info_cache; + + zend_call_known_fcc(&fcc, NULL, 1, params, NULL); + if (EG(exception)) { + OBJ_RELEASE(EG(exception)); + EG(exception) = NULL; } + OBJ_RELEASE(old_exception); - if (Z_TYPE(EG(user_exception_handler)) == IS_UNDEF) { - zval *tmp = zend_stack_top(&EG(user_exception_handlers)); - if (tmp) { - ZVAL_COPY_VALUE(&EG(user_exception_handler), tmp); - zend_stack_del_top(&EG(user_exception_handlers)); - } + if ( + current_stack_position == zend_stack_count(&EG(user_exception_handlers)) + && !ZEND_FCC_INITIALIZED(EG(user_exception_handler)) + ) { + const zend_fcall_info_cache *tmp = zend_stack_top(&EG(user_exception_handlers)); + EG(user_exception_handler) = *tmp; + zend_stack_del_top(&EG(user_exception_handlers)); } } /* }}} */ @@ -1976,7 +1974,7 @@ ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handl if (op_array) { zend_execute(op_array, retval); if (UNEXPECTED(EG(exception))) { - if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { + if (ZEND_FCC_INITIALIZED(EG(user_exception_handler))) { zend_user_exception_handler(); } if (EG(exception)) { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 34c316bca588..d38e3c0cc549 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -27,6 +27,7 @@ #include "zend_variables.h" #include "zend_execute.h" #include "zend_type_info.h" +#include "zend_user_functions.h" #include "zend_frameless_function.h" BEGIN_EXTERN_C() @@ -41,29 +42,6 @@ typedef struct _zend_function_entry { const char *doc_comment; } zend_function_entry; -typedef struct _zend_fcall_info { - size_t size; - zval function_name; - zval *retval; - zval *params; - zend_object *object; - uint32_t param_count; - uint32_t consumed_args; - /* This hashtable can also contain positional arguments (with integer keys), - * which will be appended to the normal params[]. This makes it easier to - * integrate APIs like call_user_func_array(). The usual restriction that - * there may not be position arguments after named arguments applies. */ - HashTable *named_params; -} zend_fcall_info; - -typedef struct _zend_fcall_info_cache { - zend_function *function_handler; - zend_class_entry *calling_scope; - zend_class_entry *called_scope; - zend_object *object; /* Instance of object for method calls */ - zend_object *closure; /* Closure reference, only if the callable *is* the object */ -} zend_fcall_info_cache; - #define ZEND_NS_NAME(ns, name) ns "\\" name /* ZEND_FN/ZEND_MN are inlined below to prevent pre-scan macro expansion, @@ -339,9 +317,6 @@ typedef struct _zend_fcall_info_cache { #define CE_BACKED_ENUM_TABLE(ce) \ zend_class_backed_enum_table(ce) -#define ZEND_FCI_INITIALIZED(fci) ((fci).size != 0) -#define ZEND_FCC_INITIALIZED(fcc) ((fcc).function_handler != NULL) - static zend_always_inline uint32_t zend_fci_consumed_arg(uint32_t arg_index) { return arg_index < 32 ? (UINT32_C(1) << arg_index) : UINT32_C(0); } @@ -705,14 +680,6 @@ ZEND_API zend_result _call_user_function_impl(zval *object, zval *function_name, #define call_user_function_named(function_table, object, function_name, retval_ptr, param_count, params, named_params) \ _call_user_function_impl(object, function_name, retval_ptr, param_count, params, named_params) -#ifndef __cplusplus -# define empty_fcall_info (zend_fcall_info) {0} -# define empty_fcall_info_cache (zend_fcall_info_cache) {0} -#else -# define empty_fcall_info zend_fcall_info {} -# define empty_fcall_info_cache zend_fcall_info_cache {} -#endif - /** Build zend_call_info/cache from a zval* * * Caller is responsible to provide a return value (fci->retval), otherwise the we will crash. diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 87acf073a2da..badd9ead5bc1 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1282,24 +1282,27 @@ ZEND_FUNCTION(set_error_handler) zend_long error_type = E_ALL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_FUNC_OR_NULL(fci, fcc) + Z_PARAM_FUNC_NO_TRAMPOLINE_FREE_OR_NULL(fci, fcc) // TODO: handle ZPP error for Z_PARAM_LONG Z_PARAM_OPTIONAL Z_PARAM_LONG(error_type) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { - ZVAL_COPY(return_value, &EG(user_error_handler)); + if (ZEND_FCC_INITIALIZED(EG(user_error_handler))) { + zend_get_callable_zval_from_fcc(&EG(user_error_handler), return_value); } + /* Push current error handler onto the stack, so that it can be restored later */ zend_stack_push(&EG(user_error_handlers_error_reporting), &EG(user_error_handler_error_reporting)); zend_stack_push(&EG(user_error_handlers), &EG(user_error_handler)); - if (!ZEND_FCI_INITIALIZED(fci)) { /* unset user-defined handler */ - ZVAL_UNDEF(&EG(user_error_handler)); + /* if passed null the user want's to use the default PHP error handler */ + if (!ZEND_FCC_INITIALIZED(fcc)) { + EG(user_error_handler) = empty_fcall_info_cache; return; } - ZVAL_COPY(&EG(user_error_handler), &(fci.function_name)); + zend_fcc_dup(&EG(user_error_handler), &fcc); + // TODO Need to free trampoline? EG(user_error_handler_error_reporting) = (int)error_type; } /* }}} */ @@ -1309,22 +1312,16 @@ ZEND_FUNCTION(restore_error_handler) { ZEND_PARSE_PARAMETERS_NONE(); - if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { - zval zeh; - - ZVAL_COPY_VALUE(&zeh, &EG(user_error_handler)); - ZVAL_UNDEF(&EG(user_error_handler)); - zval_ptr_dtor(&zeh); + if (ZEND_FCC_INITIALIZED(EG(user_error_handler))) { + zend_fcc_dtor(&EG(user_error_handler)); + EG(user_error_handler) = empty_fcall_info_cache; } - if (zend_stack_is_empty(&EG(user_error_handlers))) { - ZVAL_UNDEF(&EG(user_error_handler)); - } else { - zval *tmp; + if (!zend_stack_is_empty(&EG(user_error_handlers))) { EG(user_error_handler_error_reporting) = zend_stack_int_top(&EG(user_error_handlers_error_reporting)); zend_stack_del_top(&EG(user_error_handlers_error_reporting)); - tmp = zend_stack_top(&EG(user_error_handlers)); - ZVAL_COPY_VALUE(&EG(user_error_handler), tmp); + const zend_fcall_info_cache *tmp = zend_stack_top(&EG(user_error_handlers)); + EG(user_error_handler) = *tmp; zend_stack_del_top(&EG(user_error_handlers)); } @@ -1337,8 +1334,8 @@ ZEND_FUNCTION(get_error_handler) { ZEND_PARSE_PARAMETERS_NONE(); - if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { - RETURN_COPY(&EG(user_error_handler)); + if (ZEND_FCC_INITIALIZED(EG(user_error_handler))) { + zend_get_callable_zval_from_fcc(&EG(user_error_handler), return_value); } } @@ -1352,18 +1349,21 @@ ZEND_FUNCTION(set_exception_handler) Z_PARAM_FUNC_OR_NULL(fci, fcc) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { - ZVAL_COPY(return_value, &EG(user_exception_handler)); + if (ZEND_FCC_INITIALIZED(EG(user_exception_handler))) { + zend_get_callable_zval_from_fcc(&EG(user_exception_handler), return_value); } + /* Push current error handler onto the stack, so that it can be restored later */ zend_stack_push(&EG(user_exception_handlers), &EG(user_exception_handler)); - if (!ZEND_FCI_INITIALIZED(fci)) { /* unset user-defined handler */ - ZVAL_UNDEF(&EG(user_exception_handler)); + /* if passed null the user want's to use the default PHP error handler */ + if (!ZEND_FCC_INITIALIZED(fcc)) { + EG(user_exception_handler) = empty_fcall_info_cache; return; } - ZVAL_COPY(&EG(user_exception_handler), &(fci.function_name)); + zend_fcc_dup(&EG(user_exception_handler), &fcc); + // TODO Need to free trampoline? } /* }}} */ @@ -1372,14 +1372,14 @@ ZEND_FUNCTION(restore_exception_handler) { ZEND_PARSE_PARAMETERS_NONE(); - if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { - zval_ptr_dtor(&EG(user_exception_handler)); + if (ZEND_FCC_INITIALIZED(EG(user_exception_handler))) { + zend_fcc_dtor(&EG(user_exception_handler)); + EG(user_exception_handler) = empty_fcall_info_cache; } - if (zend_stack_is_empty(&EG(user_exception_handlers))) { - ZVAL_UNDEF(&EG(user_exception_handler)); - } else { - zval *tmp = zend_stack_top(&EG(user_exception_handlers)); - ZVAL_COPY_VALUE(&EG(user_exception_handler), tmp); + + if (!zend_stack_is_empty(&EG(user_exception_handlers))) { + const zend_fcall_info_cache *tmp = zend_stack_top(&EG(user_exception_handlers)); + EG(user_exception_handler) = *tmp; zend_stack_del_top(&EG(user_exception_handlers)); } @@ -1392,8 +1392,8 @@ ZEND_FUNCTION(get_exception_handler) { ZEND_PARSE_PARAMETERS_NONE(); - if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { - RETURN_COPY(&EG(user_exception_handler)); + if (ZEND_FCC_INITIALIZED(EG(user_exception_handler))) { + zend_get_callable_zval_from_fcc(&EG(user_exception_handler), return_value); } } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 3d4e6f3c3f9f..550c0704d95a 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -978,7 +978,7 @@ ZEND_API ZEND_COLD void zend_user_exception_handler(void); #define zend_try_exception_handler() do { \ if (UNEXPECTED(EG(exception))) { \ - if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { \ + if (ZEND_FCC_INITIALIZED(EG(user_exception_handler))) { \ zend_user_exception_handler(); \ } \ } \ diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index ca91ec0ce12b..e4dba57cf17f 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -183,7 +183,7 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* return; } if (EG(exception)) { - if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF + if (ZEND_FCC_INITIALIZED(EG(user_exception_handler)) && !zend_is_unwind_exit(EG(exception)) && !zend_is_graceful_exit(EG(exception))) { zend_user_exception_handler(); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 83ba5e7490cf..a50c0c9002de 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -159,14 +159,15 @@ void init_executor(void) /* {{{ */ EG(ticks_count) = 0; - ZVAL_UNDEF(&EG(user_error_handler)); - ZVAL_UNDEF(&EG(user_exception_handler)); + EG(current_executed_error_handler_stack_position) = -1; + EG(user_error_handler) = empty_fcall_info_cache; + EG(user_exception_handler) = empty_fcall_info_cache; EG(current_execute_data) = NULL; zend_stack_init(&EG(user_error_handlers_error_reporting), sizeof(int)); - zend_stack_init(&EG(user_error_handlers), sizeof(zval)); - zend_stack_init(&EG(user_exception_handlers), sizeof(zval)); + zend_stack_init(&EG(user_error_handlers), sizeof(zend_fcall_info_cache)); + zend_stack_init(&EG(user_exception_handlers), sizeof(zend_fcall_info_cache)); zend_objects_store_init(&EG(objects_store), 1024); zend_lazy_objects_init(&EG(lazy_objects_store)); @@ -268,6 +269,12 @@ void shutdown_destructors(void) /* {{{ */ } /* }}} */ +static void zend_fcc_dtor_if_set(zend_fcall_info_cache *fcc) { + if (ZEND_FCC_INITIALIZED(*fcc)) { + zend_fcc_dtor(fcc); + } +} + /* Free values held by the executor. */ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) { @@ -405,19 +412,18 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) } ZEND_HASH_FOREACH_END(); /* Also release error and exception handlers, which may hold objects. */ - if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { - zval_ptr_dtor(&EG(user_error_handler)); - ZVAL_UNDEF(&EG(user_error_handler)); + if (ZEND_FCC_INITIALIZED(EG(user_error_handler))) { + zend_fcc_dtor(&EG(user_error_handler)); + EG(user_error_handler) = empty_fcall_info_cache; } - - if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { - zval_ptr_dtor(&EG(user_exception_handler)); - ZVAL_UNDEF(&EG(user_exception_handler)); + if (ZEND_FCC_INITIALIZED(EG(user_exception_handler))) { + zend_fcc_dtor(&EG(user_exception_handler)); + EG(user_exception_handler) = empty_fcall_info_cache; } zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1); - zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1); - zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1); + zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))zend_fcc_dtor_if_set, true); + zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))zend_fcc_dtor_if_set, true); zend_hash_clean(&EG(callable_convert_cache)); zend_hash_clean(&EG(partial_function_application_cache)); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 83360a2c96d2..700c53c78134 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -42,6 +42,7 @@ #include "zend_max_execution_timer.h" #include "zend_strtod.h" #include "zend_lazy_objects.h" +#include "zend_user_functions.h" /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ @@ -241,8 +242,9 @@ struct _zend_executor_globals { int user_error_handler_error_reporting; bool exception_ignore_args; - zval user_error_handler; - zval user_exception_handler; + int current_executed_error_handler_stack_position; + zend_fcall_info_cache user_error_handler; + zend_fcall_info_cache user_exception_handler; zend_stack user_error_handlers_error_reporting; zend_stack user_error_handlers; zend_stack user_exception_handlers; diff --git a/Zend/zend_user_functions.h b/Zend/zend_user_functions.h new file mode 100644 index 000000000000..526a64d7b4ce --- /dev/null +++ b/Zend/zend_user_functions.h @@ -0,0 +1,61 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright © Zend Technologies Ltd., a subsidiary company of | + | Perforce Software, Inc., and Contributors. | + +----------------------------------------------------------------------+ + | This source file is subject to the Modified BSD License that is | + | bundled with this package in the file LICENSE, and is available | + | through the World Wide Web at . | + | | + | SPDX-License-Identifier: BSD-3-Clause | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_USER_FUNCTIONS_H +#define ZEND_USER_FUNCTIONS_H + +#include "zend_types.h" + +typedef struct _zval_struct zval; + +zend_result zend_startup_builtin_functions(void); + +BEGIN_EXTERN_C() +typedef struct _zend_fcall_info { + size_t size; + zval function_name; + zval *retval; + zval *params; + zend_object *object; + uint32_t param_count; + uint32_t consumed_args; + /* This hashtable can also contain positional arguments (with integer keys), + * which will be appended to the normal params[]. This makes it easier to + * integrate APIs like call_user_func_array(). The usual restriction that + * there may not be position arguments after named arguments applies. */ + HashTable *named_params; +} zend_fcall_info; + +typedef struct _zend_fcall_info_cache { + zend_function *function_handler; + zend_class_entry *calling_scope; + zend_class_entry *called_scope; + zend_object *object; /* Instance of object for method calls */ + zend_object *closure; /* Closure reference, only if the callable *is* the object */ +} zend_fcall_info_cache; +END_EXTERN_C() + +#ifndef __cplusplus +# define empty_fcall_info (zend_fcall_info) {0} +# define empty_fcall_info_cache (zend_fcall_info_cache) {0} +#else +# define empty_fcall_info zend_fcall_info {} +# define empty_fcall_info_cache zend_fcall_info_cache {} +#endif + +#define ZEND_FCI_INITIALIZED(fci) ((fci).size != 0) +#define ZEND_FCC_INITIALIZED(fcc) ((fcc).function_handler != NULL) + +#endif /* ZEND_USER_FUNCTIONS_H */ diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 8685fb564150..a82d718f81b1 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4857,7 +4857,7 @@ static zend_result accel_preload(const char *config, bool in_child) if (op_array) { zend_execute(op_array, NULL); if (UNEXPECTED(EG(exception))) { - if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { + if (ZEND_FCC_INITIALIZED(EG(user_exception_handler))) { zend_user_exception_handler(); } if (EG(exception)) {