Skip to content

Commit b72069e

Browse files
author
Thies C. Arntzen
committed
debug_backtrace():
- make args work if called from the error_handler - fix refcount for args
1 parent bdc35c9 commit b72069e

File tree

1 file changed

+34
-14
lines changed

1 file changed

+34
-14
lines changed

Zend/zend_builtin_functions.c

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,9 +1257,11 @@ static zval *debug_backtrace_get_args(void ***curpos TSRMLS_DC) {
12571257
MAKE_STD_ZVAL(arg_array);
12581258
array_init(arg_array);
12591259
p -= arg_count;
1260+
12601261
while (--arg_count >= 0) {
12611262
arg = (zval **) p++;
12621263
SEPARATE_ZVAL_TO_MAKE_IS_REF(arg);
1264+
(*arg)->refcount++;
12631265
add_next_index_zval(arg_array, *arg);
12641266
}
12651267
return arg_array;
@@ -1274,9 +1276,12 @@ ZEND_FUNCTION(debug_backtrace)
12741276
char *function_name;
12751277
char *filename;
12761278
char *class_name;
1279+
char *call_type;
12771280
char *include_filename = NULL;
12781281
zval *stack_frame;
1279-
void **cur_arg_pos = EG(argument_stack).top_element - 2;
1282+
void **cur_arg_pos = EG(argument_stack).top_element;
1283+
int get_args;
1284+
12801285

12811286
if (ZEND_NUM_ARGS()) {
12821287
WRONG_PARAM_COUNT;
@@ -1286,6 +1291,7 @@ ZEND_FUNCTION(debug_backtrace)
12861291

12871292
/* skip debug_backtrace() */
12881293
ptr = ptr->prev_execute_data;
1294+
cur_arg_pos -= 2;
12891295

12901296
if (ptr && cur_arg_pos[-1]) {
12911297
zend_error(E_ERROR, "debug_backtrace(): Can't be used as a function parameter");
@@ -1297,21 +1303,20 @@ ZEND_FUNCTION(debug_backtrace)
12971303
MAKE_STD_ZVAL(stack_frame);
12981304
array_init(stack_frame);
12991305

1300-
class_name = NULL;
1301-
1302-
if (ptr->object) {
1303-
class_name = Z_OBJCE(*ptr->object)->name;
1304-
add_assoc_string_ex(stack_frame, "type", sizeof("type"), "->", 1);
1305-
} else if (ptr->function_state.function->common.scope) {
1306-
class_name = ptr->function_state.function->common.scope->name;
1307-
add_assoc_string_ex(stack_frame, "type", sizeof("type"), "::", 1);
1308-
}
1309-
13101306
if (ptr->op_array) {
13111307
filename = ptr->op_array->filename;
13121308
lineno = ptr->opline->lineno;
13131309
add_assoc_string_ex(stack_frame, "file", sizeof("file"), filename, 1);
13141310
add_assoc_long_ex(stack_frame, "line", sizeof("line"), lineno);
1311+
1312+
/* try to fetch args only if an FCALL was just made - elsewise we're in the middle of a function
1313+
* and debug_baktrace() might have been called by the error_handler. in this case we don't
1314+
* want to pop anything of the argument-stack */
1315+
if ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL)) {
1316+
get_args = 1;
1317+
} else {
1318+
get_args = 0;
1319+
}
13151320
} else {
13161321
filename = NULL;
13171322
}
@@ -1321,11 +1326,25 @@ ZEND_FUNCTION(debug_backtrace)
13211326
if (function_name) {
13221327
add_assoc_string_ex(stack_frame, "function", sizeof("function"), function_name, 1);
13231328

1329+
if (ptr->object) {
1330+
class_name = Z_OBJCE(*ptr->object)->name;
1331+
call_type = "->";
1332+
add_assoc_string_ex(stack_frame, "type", sizeof("type"), "->", 1);
1333+
} else if (ptr->function_state.function->common.scope) {
1334+
class_name = ptr->function_state.function->common.scope->name;
1335+
call_type = "::";
1336+
} else {
1337+
class_name = NULL;
1338+
}
1339+
13241340
if (class_name) {
13251341
add_assoc_string_ex(stack_frame, "class", sizeof("class"), class_name, 1);
1342+
add_assoc_string_ex(stack_frame, "type", sizeof("type"), call_type, 1);
13261343
}
13271344

1328-
add_assoc_zval_ex(stack_frame, "args", sizeof("args"), debug_backtrace_get_args(&cur_arg_pos TSRMLS_CC));
1345+
if (get_args) {
1346+
add_assoc_zval_ex(stack_frame, "args", sizeof("args"), debug_backtrace_get_args(&cur_arg_pos TSRMLS_CC));
1347+
}
13291348
} else {
13301349
/* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
13311350
zend_bool build_filename_arg = 1;
@@ -1348,9 +1367,10 @@ ZEND_FUNCTION(debug_backtrace)
13481367
function_name = "require_once";
13491368
break;
13501369
default:
1351-
function_name = "unknown";
1370+
/* this can actually happen if you use debug_backtrace() in your error_handler and
1371+
* you're in the top-scope */
1372+
function_name = "unknown";
13521373
build_filename_arg = 0;
1353-
zend_error(E_ERROR, "debug_backtrece(): unable to find function-name. Please report a bug.");
13541374
break;
13551375
}
13561376

0 commit comments

Comments
 (0)