summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rwxr-xr-xZend/tests/bug29896.phpt28
-rw-r--r--Zend/zend_builtin_functions.c50
-rw-r--r--Zend/zend_execute_API.c2
4 files changed, 70 insertions, 11 deletions
diff --git a/NEWS b/NEWS
index edde30249e..95fd8eda4a 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ PHP NEWS
- Fixed bug #33427 (ext/odbc: check if unixODBC header file exists). (Jani)
- Fixed bug #33257 (array_splice() inconsistent when passed function instead
of variable). (Dmitry)
+- Fixed bug #29896 (Backtrace argument list out of sync). (Dmitry)
- Fixed bug #15854 (boolean ini options may be incorrectly displayed as Off
when they are On). (Tony)
diff --git a/Zend/tests/bug29896.phpt b/Zend/tests/bug29896.phpt
new file mode 100755
index 0000000000..1e2eb0b067
--- /dev/null
+++ b/Zend/tests/bug29896.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Bug #29896 (Backtrace argument list out of sync)
+--FILE--
+<?php
+function userErrorHandler($num, $msg, $file, $line, $vars)
+{
+ debug_print_backtrace();
+}
+
+$OldErrorHandler = set_error_handler("userErrorHandler");
+
+function GenerateError1($A1)
+{
+ $a = $b;
+}
+
+function GenerateError2($A1)
+{
+ GenerateError1("Test1");
+}
+
+GenerateError2("Test2");
+?>
+--EXPECTF--
+#0 userErrorHandler(8, Undefined variable: b, %sbug29896.php, 11, Array ([A1] => Test1)) called at [%sbug29896.php:11]
+#1 GenerateError1(Test1) called at [%sbug29896.php:16]
+#2 GenerateError2(Test2) called at [%sbug29896.php:19]
+
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 9fb2bfd68d..df4e7bd3ee 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1644,7 +1644,7 @@ void debug_print_backtrace_args(zval *arg_array TSRMLS_DC)
/* {{{ proto void debug_print_backtrace(void) */
ZEND_FUNCTION(debug_print_backtrace)
{
- zend_execute_data *ptr;
+ zend_execute_data *ptr, *skip;
int lineno;
char *function_name;
char *filename;
@@ -1689,9 +1689,21 @@ ZEND_FUNCTION(debug_print_backtrace)
class_name = call_type = NULL;
arg_array = NULL;
- if (ptr->op_array) {
- filename = ptr->op_array->filename;
- lineno = ptr->opline->lineno;
+
+ skip = ptr;
+ /* skip internal handler */
+ if (!skip->op_array &&
+ skip->prev_execute_data &&
+ skip->prev_execute_data->opline &&
+ skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL &&
+ skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME &&
+ skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
+ skip = skip->prev_execute_data;
+ }
+
+ if (skip->op_array) {
+ filename = skip->op_array->filename;
+ lineno = skip->opline->lineno;
} else {
filename = NULL;
lineno = 0;
@@ -1770,7 +1782,7 @@ ZEND_FUNCTION(debug_print_backtrace)
}
zend_printf(") called at [%s:%d]\n", filename, lineno);
include_filename = filename;
- ptr = ptr->prev_execute_data;
+ ptr = skip->prev_execute_data;
++indent;
if (free_class_name) {
efree(free_class_name);
@@ -1782,7 +1794,7 @@ ZEND_FUNCTION(debug_print_backtrace)
ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last TSRMLS_DC)
{
- zend_execute_data *ptr;
+ zend_execute_data *ptr, *skip;
int lineno;
char *function_name;
char *filename;
@@ -1809,12 +1821,17 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last TSRML
ptr = EG(current_execute_data);
+ /* skip "new Exception()" */
+ if ((skip_last == 0) && ptr->opline && (ptr->opline->opcode == ZEND_NEW)) {
+ ptr = ptr->prev_execute_data;
+ }
+
/* skip debug_backtrace() */
- ptr = ptr->prev_execute_data;
if (skip_last--) {
int arg_count = *((ulong*)(cur_arg_pos - 2));
cur_arg_pos -= (arg_count + 2);
frames_on_stack--;
+ ptr = ptr->prev_execute_data;
}
array_init(return_value);
@@ -1823,9 +1840,20 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last TSRML
MAKE_STD_ZVAL(stack_frame);
array_init(stack_frame);
- if (ptr->op_array) {
- filename = ptr->op_array->filename;
- lineno = ptr->opline->lineno;
+ skip = ptr;
+ /* skip internal handler */
+ if (!skip->op_array &&
+ skip->prev_execute_data &&
+ skip->prev_execute_data->opline &&
+ skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL &&
+ skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME &&
+ skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
+ skip = skip->prev_execute_data;
+ }
+
+ if (skip->op_array) {
+ filename = skip->op_array->filename;
+ lineno = skip->opline->lineno;
add_assoc_string_ex(stack_frame, "file", sizeof("file"), filename, 1);
add_assoc_long_ex(stack_frame, "line", sizeof("line"), lineno);
@@ -1916,7 +1944,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last TSRML
include_filename = filename;
- ptr = ptr->prev_execute_data;
+ ptr = skip->prev_execute_data;
}
}
/* }}} */
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 8c527ec591..82e59f7651 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -587,6 +587,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
/* Initialize execute_data */
if (EG(current_execute_data)) {
execute_data = *EG(current_execute_data);
+ EX(op_array) = NULL;
+ EX(opline) = NULL;
} else {
/* This only happens when we're called outside any execute()'s
* It shouldn't be strictly necessary to NULL execute_data out,