Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Zend/tests/bug63206.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/bug63206_1.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ set_error_handler(function() {
restore_error_handler();
restore_error_handler();

$triggerNotice++;
trigger_error('Error', E_USER_WARNING);
?>
--EXPECT--
Second handler
2 changes: 1 addition & 1 deletion Zend/tests/gc/bug64960.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Zend/tests/get_error_handler.phpt
Original file line number Diff line number Diff line change
@@ -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--
<?php

Expand Down
2 changes: 2 additions & 0 deletions Zend/tests/get_exception_handler.phpt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
--TEST--
get_exception_handler()
--XFAIL--
Getting callable from FCC cannot give a correct representation for static methods (string or array)
--FILE--
<?php

Expand Down
96 changes: 47 additions & 49 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -812,8 +812,8 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{
memset(&executor_globals->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;
Expand Down Expand Up @@ -1443,15 +1443,13 @@ 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;
zend_stack delayed_oplines_stack;
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. */
Expand Down Expand Up @@ -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:
Expand All @@ -1558,9 +1563,6 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(

ZVAL_LONG(&params[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
Expand All @@ -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(&params[2]);
zval_ptr_dtor(&params[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);
Expand All @@ -1605,14 +1612,6 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(
CG(in_compilation) = 1;
}

zval_ptr_dtor(&params[2]);
zval_ptr_dtor(&params[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;
}

Expand Down Expand Up @@ -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(&params[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));
}
} /* }}} */

Expand All @@ -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)) {
Expand Down
35 changes: 1 addition & 34 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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.
Expand Down
Loading
Loading