mirror of
https://github.com/bdnugget/php-src.git
synced 2026-11-07 09:17:29 +00:00
Stop inserting fake frames on VM stack.
Now similar "fake" frames now materialized when fetching debug backtraces. The patch also fixes few incorrect backtraces for generators in *.phpt tests.
This commit is contained in:
1 parent
7af3a392f1
commit
ca49e53670
8 files changed
+177
-199
No files matched your search
@@ -26,5 +26,6 @@ before yield in finally
|
||||
|
||||
Fatal error: Uncaught Error: Cannot yield from finally in a force-closed generator in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
#0 [internal function]: gen()
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
||||
+105
-136
@@ -1661,25 +1661,12 @@ void debug_print_backtrace_args(zval *arg_array) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static inline bool skip_internal_handler(zend_execute_data *skip) /* {{{ */
|
||||
{
|
||||
return !(skip->func && ZEND_USER_CODE(skip->func->common.type))
|
||||
&& skip->prev_execute_data
|
||||
&& skip->prev_execute_data->func
|
||||
&& ZEND_USER_CODE(skip->prev_execute_data->func->common.type)
|
||||
&& skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL
|
||||
&& skip->prev_execute_data->opline->opcode != ZEND_DO_ICALL
|
||||
&& skip->prev_execute_data->opline->opcode != ZEND_DO_UCALL
|
||||
&& skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME
|
||||
&& skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL;
|
||||
}
|
||||
/* {{{ */
|
||||
|
||||
/* {{{ */
|
||||
ZEND_FUNCTION(debug_print_backtrace)
|
||||
{
|
||||
zend_execute_data *call, *ptr, *skip;
|
||||
zend_execute_data *call;
|
||||
zend_object *object;
|
||||
bool fake_frame = 0;
|
||||
int lineno, frameno = 0;
|
||||
zend_function *func;
|
||||
const char *function_name;
|
||||
@@ -1696,61 +1683,67 @@ ZEND_FUNCTION(debug_print_backtrace)
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
ZVAL_UNDEF(&arg_array);
|
||||
ptr = EX(prev_execute_data);
|
||||
|
||||
/* skip debug_backtrace() */
|
||||
call = ptr;
|
||||
ptr = ptr->prev_execute_data;
|
||||
call = EX(prev_execute_data);
|
||||
|
||||
while (call && (limit == 0 || frameno < limit)) {
|
||||
zend_execute_data *prev = call->prev_execute_data;
|
||||
|
||||
if (!prev) {
|
||||
/* add frame for a handler call without {main} code */
|
||||
if (EXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_TOP_FUNCTION) == 0)) {
|
||||
break;
|
||||
}
|
||||
} else if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_GENERATOR) != 0)) {
|
||||
prev = zend_generator_check_placeholder_frame(prev);
|
||||
}
|
||||
|
||||
while (ptr && (limit == 0 || frameno < limit)) {
|
||||
frameno++;
|
||||
class_name = NULL;
|
||||
call_type = NULL;
|
||||
ZVAL_UNDEF(&arg_array);
|
||||
|
||||
if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_GENERATOR) != 0)) {
|
||||
ptr = zend_generator_check_placeholder_frame(ptr);
|
||||
}
|
||||
|
||||
skip = ptr;
|
||||
/* skip internal handler */
|
||||
if (skip_internal_handler(skip)) {
|
||||
skip = skip->prev_execute_data;
|
||||
}
|
||||
|
||||
if (skip->func && ZEND_USER_CODE(skip->func->common.type)) {
|
||||
filename = ZSTR_VAL(skip->func->op_array.filename);
|
||||
if (skip->opline->opcode == ZEND_HANDLE_EXCEPTION) {
|
||||
if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
|
||||
filename = ZSTR_VAL(prev->func->op_array.filename);
|
||||
if (prev->opline->opcode == ZEND_HANDLE_EXCEPTION) {
|
||||
if (EG(opline_before_exception)) {
|
||||
lineno = EG(opline_before_exception)->lineno;
|
||||
} else {
|
||||
lineno = skip->func->op_array.line_end;
|
||||
lineno = prev->func->op_array.line_end;
|
||||
}
|
||||
} else {
|
||||
lineno = skip->opline->lineno;
|
||||
lineno = prev->opline->lineno;
|
||||
}
|
||||
} else {
|
||||
zend_execute_data *prev_call = prev;
|
||||
|
||||
filename = NULL;
|
||||
lineno = 0;
|
||||
while (prev_call) {
|
||||
zend_execute_data *prev;
|
||||
|
||||
if (prev_call &&
|
||||
prev_call->func &&
|
||||
!ZEND_USER_CODE(prev_call->func->common.type) &&
|
||||
!(prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev = prev_call->prev_execute_data;
|
||||
if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
|
||||
filename = ZSTR_VAL(prev->func->op_array.filename);
|
||||
lineno = prev->opline->lineno;
|
||||
break;
|
||||
}
|
||||
prev_call = prev;
|
||||
}
|
||||
}
|
||||
|
||||
/* $this may be passed into regular internal functions */
|
||||
object = (Z_TYPE(call->This) == IS_OBJECT) ? Z_OBJ(call->This) : NULL;
|
||||
|
||||
if (call->func) {
|
||||
func = call->func;
|
||||
if (func->common.function_name) {
|
||||
function_name = ZSTR_VAL(func->common.function_name);
|
||||
} else {
|
||||
function_name = NULL;
|
||||
}
|
||||
} else {
|
||||
func = NULL;
|
||||
function_name = NULL;
|
||||
}
|
||||
|
||||
if (function_name) {
|
||||
func = call->func;
|
||||
if (!fake_frame && func->common.function_name) {
|
||||
function_name = ZSTR_VAL(func->common.function_name);
|
||||
if (object) {
|
||||
if (func->common.scope) {
|
||||
class_name = func->common.scope->name;
|
||||
@@ -1777,8 +1770,8 @@ ZEND_FUNCTION(debug_print_backtrace)
|
||||
/* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
|
||||
bool build_filename_arg = 1;
|
||||
uint32_t include_kind = 0;
|
||||
if (ptr->func && ZEND_USER_CODE(ptr->func->common.type) && ptr->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
|
||||
include_kind = ptr->opline->extended_value;
|
||||
if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type) && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
|
||||
include_kind = prev->opline->extended_value;
|
||||
}
|
||||
|
||||
switch (include_kind) {
|
||||
@@ -1833,33 +1826,22 @@ ZEND_FUNCTION(debug_print_backtrace)
|
||||
if (filename) {
|
||||
zend_printf(") called at [%s:%d]\n", filename, lineno);
|
||||
} else {
|
||||
zend_execute_data *prev_call = skip;
|
||||
zend_execute_data *prev = skip->prev_execute_data;
|
||||
|
||||
while (prev) {
|
||||
if (prev_call &&
|
||||
prev_call->func &&
|
||||
!ZEND_USER_CODE(prev_call->func->common.type)) {
|
||||
prev = NULL;
|
||||
break;
|
||||
}
|
||||
if (prev->func && ZEND_USER_CODE(prev->func->common.type)) {
|
||||
zend_printf(") called at [%s:%d]\n", ZSTR_VAL(prev->func->op_array.filename), prev->opline->lineno);
|
||||
break;
|
||||
}
|
||||
prev_call = prev;
|
||||
prev = prev->prev_execute_data;
|
||||
}
|
||||
if (!prev) {
|
||||
ZEND_PUTS(")\n");
|
||||
}
|
||||
ZEND_PUTS(")\n");
|
||||
}
|
||||
++indent;
|
||||
|
||||
skip_frame:
|
||||
include_filename = filename;
|
||||
call = skip;
|
||||
ptr = skip->prev_execute_data;
|
||||
if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_TOP_FUNCTION) != 0)
|
||||
&& !fake_frame
|
||||
&& prev
|
||||
&& prev->func
|
||||
&& ZEND_USER_CODE(prev->func->common.type)
|
||||
&& prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
|
||||
fake_frame = 1;
|
||||
} else {
|
||||
include_filename = filename;
|
||||
call = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1867,11 +1849,11 @@ skip_frame:
|
||||
|
||||
ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit) /* {{{ */
|
||||
{
|
||||
zend_execute_data *ptr, *skip, *call = NULL;
|
||||
zend_execute_data *call;
|
||||
zend_object *object;
|
||||
bool fake_frame = 0;
|
||||
int lineno, frameno = 0;
|
||||
zend_function *func;
|
||||
zend_string *function_name;
|
||||
zend_string *filename;
|
||||
zend_string *include_filename = NULL;
|
||||
zval tmp;
|
||||
@@ -1879,60 +1861,44 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
||||
|
||||
array_init(return_value);
|
||||
|
||||
if (!(ptr = EG(current_execute_data))) {
|
||||
call = EG(current_execute_data);
|
||||
if (!call) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ptr->func || !ZEND_USER_CODE(ptr->func->common.type)) {
|
||||
call = ptr;
|
||||
ptr = ptr->prev_execute_data;
|
||||
if (skip_last) {
|
||||
/* skip debug_backtrace() */
|
||||
call = call->prev_execute_data;
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
if (skip_last) {
|
||||
/* skip debug_backtrace() */
|
||||
call = ptr;
|
||||
ptr = ptr->prev_execute_data;
|
||||
} else {
|
||||
/* skip "new Exception()" */
|
||||
if (ptr->func && ZEND_USER_CODE(ptr->func->common.type) && (ptr->opline->opcode == ZEND_NEW)) {
|
||||
call = ptr;
|
||||
ptr = ptr->prev_execute_data;
|
||||
while (call && (limit == 0 || frameno < limit)) {
|
||||
zend_execute_data *prev = call->prev_execute_data;
|
||||
|
||||
if (!prev) {
|
||||
/* add frame for a handler call without {main} code */
|
||||
if (EXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_TOP_FUNCTION) == 0)) {
|
||||
break;
|
||||
}
|
||||
} else if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_GENERATOR) != 0)) {
|
||||
prev = zend_generator_check_placeholder_frame(prev);
|
||||
}
|
||||
if (!call) {
|
||||
call = ptr;
|
||||
ptr = ptr->prev_execute_data;
|
||||
}
|
||||
}
|
||||
|
||||
while (ptr && (limit == 0 || frameno < limit)) {
|
||||
frameno++;
|
||||
|
||||
/* We use _zend_hash_append*() and the array must be preallocated */
|
||||
stack_frame = zend_new_array(8);
|
||||
zend_hash_real_init_mixed(stack_frame);
|
||||
|
||||
if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_GENERATOR) != 0)) {
|
||||
ptr = zend_generator_check_placeholder_frame(ptr);
|
||||
}
|
||||
|
||||
skip = ptr;
|
||||
/* skip internal handler */
|
||||
if (skip_internal_handler(skip)) {
|
||||
skip = skip->prev_execute_data;
|
||||
}
|
||||
|
||||
if (skip->func && ZEND_USER_CODE(skip->func->common.type)) {
|
||||
filename = skip->func->op_array.filename;
|
||||
if (skip->opline->opcode == ZEND_HANDLE_EXCEPTION) {
|
||||
if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
|
||||
filename = prev->func->op_array.filename;
|
||||
if (prev->opline->opcode == ZEND_HANDLE_EXCEPTION) {
|
||||
if (EG(opline_before_exception)) {
|
||||
lineno = EG(opline_before_exception)->lineno;
|
||||
} else {
|
||||
lineno = skip->func->op_array.line_end;
|
||||
lineno = prev->func->op_array.line_end;
|
||||
}
|
||||
} else {
|
||||
lineno = skip->opline->lineno;
|
||||
lineno = prev->opline->lineno;
|
||||
}
|
||||
ZVAL_STR_COPY(&tmp, filename);
|
||||
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
|
||||
@@ -1943,17 +1909,20 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
||||
* and debug_backtrace() might have been called by the error_handler. in this case we don't
|
||||
* want to pop anything of the argument-stack */
|
||||
} else {
|
||||
zend_execute_data *prev_call = skip;
|
||||
zend_execute_data *prev = skip->prev_execute_data;
|
||||
zend_execute_data *prev_call = prev;
|
||||
|
||||
while (prev_call) {
|
||||
zend_execute_data *prev;
|
||||
|
||||
while (prev) {
|
||||
if (prev_call &&
|
||||
prev_call->func &&
|
||||
!ZEND_USER_CODE(prev_call->func->common.type) &&
|
||||
!(prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
|
||||
break;
|
||||
}
|
||||
if (prev->func && ZEND_USER_CODE(prev->func->common.type)) {
|
||||
|
||||
prev = prev_call->prev_execute_data;
|
||||
if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
|
||||
ZVAL_STR_COPY(&tmp, prev->func->op_array.filename);
|
||||
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
|
||||
ZVAL_LONG(&tmp, prev->opline->lineno);
|
||||
@@ -1961,27 +1930,18 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
||||
break;
|
||||
}
|
||||
prev_call = prev;
|
||||
prev = prev->prev_execute_data;
|
||||
}
|
||||
filename = NULL;
|
||||
}
|
||||
|
||||
/* $this may be passed into regular internal functions */
|
||||
object = (call && (Z_TYPE(call->This) == IS_OBJECT)) ? Z_OBJ(call->This) : NULL;
|
||||
|
||||
if (call && call->func) {
|
||||
func = call->func;
|
||||
function_name = func->common.function_name;
|
||||
} else {
|
||||
func = NULL;
|
||||
function_name = NULL;
|
||||
}
|
||||
|
||||
if (function_name) {
|
||||
ZVAL_STR_COPY(&tmp, function_name);
|
||||
func = call->func;
|
||||
if (!fake_frame && func->common.function_name) {
|
||||
ZVAL_STR_COPY(&tmp, func->common.function_name);
|
||||
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
|
||||
|
||||
if (object) {
|
||||
if (Z_TYPE(call->This) == IS_OBJECT) {
|
||||
object = Z_OBJ(call->This);
|
||||
/* $this may be passed into regular internal functions */
|
||||
if (func->common.scope) {
|
||||
ZVAL_STR_COPY(&tmp, func->common.scope->name);
|
||||
} else if (object->handlers->get_class_name == zend_std_get_class_name) {
|
||||
@@ -2015,8 +1975,8 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
||||
bool build_filename_arg = 1;
|
||||
zend_string *pseudo_function_name;
|
||||
uint32_t include_kind = 0;
|
||||
if (ptr->func && ZEND_USER_CODE(ptr->func->common.type) && ptr->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
|
||||
include_kind = ptr->opline->extended_value;
|
||||
if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type) && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
|
||||
include_kind = prev->opline->extended_value;
|
||||
}
|
||||
|
||||
switch (include_kind) {
|
||||
@@ -2070,9 +2030,18 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
||||
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
|
||||
|
||||
skip_frame:
|
||||
include_filename = filename;
|
||||
call = skip;
|
||||
ptr = skip->prev_execute_data;
|
||||
if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_TOP_FUNCTION) != 0)
|
||||
&& !fake_frame
|
||||
&& prev
|
||||
&& prev->func
|
||||
&& ZEND_USER_CODE(prev->func->common.type)
|
||||
&& prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
|
||||
fake_frame = 1;
|
||||
} else {
|
||||
fake_frame = 0;
|
||||
include_filename = filename;
|
||||
call = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -276,7 +276,7 @@ static zend_object *zend_default_exception_new(zend_class_entry *class_type) /*
|
||||
|
||||
static zend_object *zend_error_exception_new(zend_class_entry *class_type) /* {{{ */
|
||||
{
|
||||
return zend_default_exception_new_ex(class_type, 2);
|
||||
return zend_default_exception_new_ex(class_type, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
+5
-55
@@ -683,7 +683,7 @@ zend_result _call_user_function_impl(zval *object, zval *function_name, zval *re
|
||||
zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /* {{{ */
|
||||
{
|
||||
uint32_t i;
|
||||
zend_execute_data *call, dummy_execute_data;
|
||||
zend_execute_data *call;
|
||||
zend_fcall_info_cache fci_cache_local;
|
||||
zend_function *func;
|
||||
uint32_t call_info;
|
||||
@@ -702,29 +702,6 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
|
||||
|
||||
ZEND_ASSERT(fci->size == sizeof(zend_fcall_info));
|
||||
|
||||
/* Initialize execute_data */
|
||||
if (!EG(current_execute_data)) {
|
||||
/* This only happens when we're called outside any execute()'s
|
||||
* It shouldn't be strictly necessary to NULL execute_data out,
|
||||
* but it may make bugs easier to spot
|
||||
*/
|
||||
memset(&dummy_execute_data, 0, sizeof(zend_execute_data));
|
||||
EG(current_execute_data) = &dummy_execute_data;
|
||||
} else if (EG(current_execute_data)->func &&
|
||||
ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
|
||||
EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL &&
|
||||
EG(current_execute_data)->opline->opcode != ZEND_DO_ICALL &&
|
||||
EG(current_execute_data)->opline->opcode != ZEND_DO_UCALL &&
|
||||
EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL_BY_NAME) {
|
||||
/* Insert fake frame in case of include or magic calls */
|
||||
dummy_execute_data = *EG(current_execute_data);
|
||||
dummy_execute_data.prev_execute_data = EG(current_execute_data);
|
||||
dummy_execute_data.call = NULL;
|
||||
dummy_execute_data.opline = NULL;
|
||||
dummy_execute_data.func = NULL;
|
||||
EG(current_execute_data) = &dummy_execute_data;
|
||||
}
|
||||
|
||||
if (!fci_cache || !fci_cache->function_handler) {
|
||||
char *error = NULL;
|
||||
|
||||
@@ -740,9 +717,6 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
|
||||
efree(error);
|
||||
zend_string_release_ex(callable_name, 0);
|
||||
}
|
||||
if (EG(current_execute_data) == &dummy_execute_data) {
|
||||
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
@@ -768,10 +742,6 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
|
||||
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
zend_vm_stack_free_call_frame(call);
|
||||
if (EG(current_execute_data) == &dummy_execute_data) {
|
||||
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
|
||||
zend_rethrow_exception(EG(current_execute_data));
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
@@ -799,9 +769,6 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
|
||||
cleanup_args:
|
||||
zend_vm_stack_free_args(call);
|
||||
zend_vm_stack_free_call_frame(call);
|
||||
if (EG(current_execute_data) == &dummy_execute_data) {
|
||||
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
@@ -885,9 +852,6 @@ cleanup_args:
|
||||
if (zend_handle_undef_args(call) == FAILURE) {
|
||||
zend_vm_stack_free_args(call);
|
||||
zend_vm_stack_free_call_frame(call);
|
||||
if (EG(current_execute_data) == &dummy_execute_data) {
|
||||
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -903,25 +867,20 @@ cleanup_args:
|
||||
ZEND_ADD_CALL_FLAG(call, call_info);
|
||||
}
|
||||
|
||||
if (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
|
||||
fci_cache->function_handler = NULL;
|
||||
}
|
||||
|
||||
orig_fake_scope = EG(fake_scope);
|
||||
EG(fake_scope) = NULL;
|
||||
if (func->type == ZEND_USER_FUNCTION) {
|
||||
int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
|
||||
const zend_op *current_opline_before_exception = EG(opline_before_exception);
|
||||
uint32_t orig_jit_trace_num = EG(jit_trace_num);
|
||||
|
||||
zend_init_func_execute_data(call, &func->op_array, fci->retval);
|
||||
ZEND_OBSERVER_FCALL_BEGIN(call);
|
||||
zend_execute_ex(call);
|
||||
EG(jit_trace_num) = orig_jit_trace_num;
|
||||
EG(opline_before_exception) = current_opline_before_exception;
|
||||
if (call_via_handler) {
|
||||
/* We must re-initialize function again */
|
||||
fci_cache->function_handler = NULL;
|
||||
}
|
||||
} else {
|
||||
int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
|
||||
|
||||
ZEND_ASSERT(func->type == ZEND_INTERNAL_FUNCTION);
|
||||
ZVAL_NULL(fci->retval);
|
||||
call->prev_execute_data = EG(current_execute_data);
|
||||
@@ -943,11 +902,6 @@ cleanup_args:
|
||||
ZVAL_UNDEF(fci->retval);
|
||||
}
|
||||
|
||||
if (call_via_handler) {
|
||||
/* We must re-initialize function again */
|
||||
fci_cache->function_handler = NULL;
|
||||
}
|
||||
|
||||
/* This flag is regularly checked while running user functions, but not internal
|
||||
* So see whether interrupt flag was set while the function was running... */
|
||||
if (EG(vm_interrupt)) {
|
||||
@@ -963,10 +917,6 @@ cleanup_args:
|
||||
|
||||
zend_vm_stack_free_call_frame(call);
|
||||
|
||||
if (EG(current_execute_data) == &dummy_execute_data) {
|
||||
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
if (UNEXPECTED(!EG(current_execute_data))) {
|
||||
zend_throw_exception_internal(NULL);
|
||||
|
||||
@@ -97,6 +97,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
|
||||
|
||||
if (destructor) {
|
||||
zend_object *old_exception;
|
||||
const zend_op *old_opline_before_exception;
|
||||
|
||||
if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
|
||||
if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
|
||||
@@ -156,6 +157,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
|
||||
zend_error_noreturn(E_CORE_ERROR, "Attempt to destruct pending exception");
|
||||
} else {
|
||||
old_exception = EG(exception);
|
||||
old_opline_before_exception = EG(opline_before_exception);
|
||||
EG(exception) = NULL;
|
||||
}
|
||||
}
|
||||
@@ -163,6 +165,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
|
||||
zend_call_known_instance_method_with_0_params(destructor, object, NULL);
|
||||
|
||||
if (old_exception) {
|
||||
EG(opline_before_exception) = old_opline_before_exception;
|
||||
if (EG(exception)) {
|
||||
zend_exception_set_previous(EG(exception), old_exception);
|
||||
} else {
|
||||
|
||||
@@ -37,7 +37,7 @@ foreach ($gens as $gen) {
|
||||
--EXPECTF--
|
||||
object(Generator)#2 (0) {
|
||||
}
|
||||
array(1) {
|
||||
array(2) {
|
||||
[0]=>
|
||||
array(4) {
|
||||
["file"]=>
|
||||
@@ -50,6 +50,21 @@ array(1) {
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
[1]=>
|
||||
array(5) {
|
||||
["function"]=>
|
||||
string(1) "a"
|
||||
["class"]=>
|
||||
string(%d) "class@anonymous%s"
|
||||
["object"]=>
|
||||
object(class@anonymous)#%d (0) {
|
||||
}
|
||||
["type"]=>
|
||||
string(2) "->"
|
||||
["args"]=>
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
int(%d)
|
||||
string(%d) "%sReflectionGenerator_basic.%s"
|
||||
@@ -65,7 +80,15 @@ object(class@anonymous)#1 (0) {
|
||||
}
|
||||
object(Generator)#4 (0) {
|
||||
}
|
||||
array(0) {
|
||||
array(1) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["function"]=>
|
||||
string(9) "{closure}"
|
||||
["args"]=>
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
int(%d)
|
||||
string(%d) "%sReflectionGenerator_basic.%s"
|
||||
@@ -78,7 +101,15 @@ object(ReflectionFunction)#7 (1) {
|
||||
NULL
|
||||
object(Generator)#5 (0) {
|
||||
}
|
||||
array(0) {
|
||||
array(1) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["function"]=>
|
||||
string(3) "foo"
|
||||
["args"]=>
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
int(%d)
|
||||
string(%d) "%sReflectionGenerator_basic.%s"
|
||||
|
||||
@@ -25,7 +25,7 @@ var_dump((new ReflectionGenerator($gen))->getTrace());
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
array(2) {
|
||||
array(3) {
|
||||
[0]=>
|
||||
array(4) {
|
||||
["file"]=>
|
||||
@@ -50,4 +50,12 @@ array(2) {
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
[2]=>
|
||||
array(2) {
|
||||
["function"]=>
|
||||
string(3) "baz"
|
||||
["args"]=>
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,15 @@ function doCalls(ReflectionGenerator $ref) {
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
array(0) {
|
||||
array(1) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["function"]=>
|
||||
string(9) "{closure}"
|
||||
["args"]=>
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
int(%d)
|
||||
string(%d) "%sReflectionGenerator_in_Generator.%s"
|
||||
@@ -44,7 +52,7 @@ object(ReflectionFunction)#4 (1) {
|
||||
string(9) "{closure}"
|
||||
}
|
||||
NULL
|
||||
array(1) {
|
||||
array(2) {
|
||||
[0]=>
|
||||
array(4) {
|
||||
["file"]=>
|
||||
@@ -57,6 +65,14 @@ array(1) {
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["function"]=>
|
||||
string(9) "{closure}"
|
||||
["args"]=>
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
int(%d)
|
||||
string(%d) "%sReflectionGenerator_in_Generator.%s"
|
||||
|
||||
Reference in new issue
Block a user