Skip to content

Commit 450f2ff

Browse files
committed
Skip unnecessary unknown() frames
Noticed this while working on attributes strict_types handling. We sometimes insert dummy frames internally, but I don't think these should show up in debug_backtrace output unless they're needed, either to display an include call or to preserve file/line information that would otherwise get lost. Closes GH-6195.
1 parent be4553b commit 450f2ff

File tree

3 files changed

+29
-24
lines changed

3 files changed

+29
-24
lines changed

Zend/zend_builtin_functions.c

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,13 +1781,12 @@ ZEND_FUNCTION(debug_print_backtrace)
17811781
} else {
17821782
/* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
17831783
zend_bool build_filename_arg = 1;
1784+
uint32_t include_kind = 0;
1785+
if (ptr->func && ZEND_USER_CODE(ptr->func->common.type) && ptr->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
1786+
include_kind = ptr->opline->extended_value;
1787+
}
17841788

1785-
if (!ptr->func || !ZEND_USER_CODE(ptr->func->common.type) || ptr->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
1786-
/* can happen when calling eval from a custom sapi */
1787-
function_name = "unknown";
1788-
build_filename_arg = 0;
1789-
} else
1790-
switch (ptr->opline->extended_value) {
1789+
switch (include_kind) {
17911790
case ZEND_EVAL:
17921791
function_name = "eval";
17931792
build_filename_arg = 0;
@@ -1805,8 +1804,11 @@ ZEND_FUNCTION(debug_print_backtrace)
18051804
function_name = "require_once";
18061805
break;
18071806
default:
1808-
/* this can actually happen if you use debug_backtrace() in your error_handler and
1809-
* you're in the top-scope */
1807+
/* Skip dummy frame unless it is needed to preserve filename/lineno info. */
1808+
if (!filename) {
1809+
goto skip_frame;
1810+
}
1811+
18101812
function_name = "unknown";
18111813
build_filename_arg = 0;
18121814
break;
@@ -1857,10 +1859,12 @@ ZEND_FUNCTION(debug_print_backtrace)
18571859
ZEND_PUTS(")\n");
18581860
}
18591861
}
1862+
++indent;
1863+
1864+
skip_frame:
18601865
include_filename = filename;
18611866
call = skip;
18621867
ptr = skip->prev_execute_data;
1863-
++indent;
18641868
}
18651869
}
18661870

@@ -2009,13 +2013,12 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
20092013
/* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
20102014
zend_bool build_filename_arg = 1;
20112015
zend_string *pseudo_function_name;
2016+
uint32_t include_kind = 0;
2017+
if (ptr->func && ZEND_USER_CODE(ptr->func->common.type) && ptr->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
2018+
include_kind = ptr->opline->extended_value;
2019+
}
20122020

2013-
if (!ptr->func || !ZEND_USER_CODE(ptr->func->common.type) || ptr->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
2014-
/* can happen when calling eval from a custom sapi */
2015-
pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN);
2016-
build_filename_arg = 0;
2017-
} else
2018-
switch (ptr->opline->extended_value) {
2021+
switch (include_kind) {
20192022
case ZEND_EVAL:
20202023
pseudo_function_name = ZSTR_KNOWN(ZEND_STR_EVAL);
20212024
build_filename_arg = 0;
@@ -2033,8 +2036,12 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
20332036
pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE_ONCE);
20342037
break;
20352038
default:
2036-
/* this can actually happen if you use debug_backtrace() in your error_handler and
2037-
* you're in the top-scope */
2039+
/* Skip dummy frame unless it is needed to preserve filename/lineno info. */
2040+
if (!filename) {
2041+
zval_ptr_dtor(&stack_frame);
2042+
goto skip_frame;
2043+
}
2044+
20382045
pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN);
20392046
build_filename_arg = 0;
20402047
break;
@@ -2060,8 +2067,8 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
20602067

20612068
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &stack_frame);
20622069

2070+
skip_frame:
20632071
include_filename = filename;
2064-
20652072
call = skip;
20662073
ptr = skip->prev_execute_data;
20672074
}

ext/phar/tests/cache_list/frontcontroller29.phpt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ Content-type: text/html; charset=UTF-8
1616
--EXPECTF--
1717
Fatal error: Uncaught Error: Call to undefined function oopsie_daisy() in phar://%sfatalerror.phps:1
1818
Stack trace:
19-
#0 [internal function]: unknown()
20-
#1 %s(%d): Phar::webPhar('whatever', 'index.php', '404.php', Array)
21-
#2 {main}
19+
#0 %s(%d): Phar::webPhar('whatever', 'index.php', '404.php', Array)
20+
#1 {main}
2221
thrown in phar://%sfatalerror.phps on line 1

ext/phar/tests/frontcontroller29.phpt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ Content-type: text/html; charset=UTF-8
1515
--EXPECTF--
1616
Fatal error: Uncaught Error: Call to undefined function oopsie_daisy() in phar://%sfatalerror.phps:1
1717
Stack trace:
18-
#0 [internal function]: unknown()
19-
#1 %s(%d): Phar::webPhar('whatever', 'index.php', '404.php', Array)
20-
#2 {main}
18+
#0 %s(%d): Phar::webPhar('whatever', 'index.php', '404.php', Array)
19+
#1 {main}
2120
thrown in phar://%sfatalerror.phps on line 1

0 commit comments

Comments
 (0)