Skip to content

Commit a5cef84

Browse files
committed
Fix bug #24214 implement access to skip_last in user API for backtrace
1 parent 131887d commit a5cef84

6 files changed

+89
-9
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ PHP NEWS
1313
(Björn Tantau)
1414
. Fixed bug #81076 (incorrect debug info on Closures with implicit binds).
1515
(krakjoe)
16+
. Fixed bug #24214 (implement skipping frames in backtraces). (krakjoe)
1617

1718
- Standard:
1819
. Fixed bug #77627 (method_exists on Closure::__invoke inconsistency).
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
debug_backtrace skip_last parameter
3+
--FILE--
4+
<?php
5+
(function(){
6+
(function(){
7+
return (function() {
8+
foreach (debug_backtrace(skip_last: 0) as $frame) {
9+
printf("%s in %s on line %d\n", $frame["function"], $frame["file"], $frame["line"]);
10+
}
11+
echo PHP_EOL;
12+
foreach (debug_backtrace(skip_last: 1) as $frame) {
13+
printf("%s in %s on line %d\n", $frame["function"], $frame["file"], $frame["line"]);
14+
}
15+
echo PHP_EOL;
16+
foreach (debug_backtrace(skip_last: 2) as $frame) {
17+
printf("%s in %s on line %d\n", $frame["function"], $frame["file"], $frame["line"]);
18+
}
19+
echo PHP_EOL;
20+
foreach (debug_backtrace(skip_last: 3) as $frame) {
21+
printf("%s in %s on line %d\n", $frame["function"], $frame["file"], $frame["line"]);
22+
}
23+
})();
24+
})();
25+
})();
26+
?>
27+
--EXPECTF--
28+
debug_backtrace in %s on line 5
29+
{closure} in %s on line 20
30+
{closure} in %s on line 21
31+
{closure} in %s on line 22
32+
33+
{closure} in %s on line 20
34+
{closure} in %s on line 21
35+
{closure} in %s on line 22
36+
37+
{closure} in %s on line 21
38+
{closure} in %s on line 22
39+
40+
{closure} in %s on line 22
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
debug_print_backtrace skip_last parameter
3+
--FILE--
4+
<?php
5+
(function(){
6+
(function(){
7+
return (function() {
8+
debug_print_backtrace(skip_last: 0);
9+
echo PHP_EOL;
10+
debug_print_backtrace(skip_last: 1);
11+
echo PHP_EOL;
12+
debug_print_backtrace(skip_last: 2);
13+
echo PHP_EOL;
14+
debug_print_backtrace(skip_last: 3);
15+
})();
16+
})();
17+
})();
18+
?>
19+
--EXPECTF--
20+
#0 %s(5): debug_print_backtrace(0, 0, 0)
21+
#1 %s(12): {closure}()
22+
#2 %s(13): {closure}()
23+
#3 %s(14): {closure}()
24+
25+
#0 %s(12): {closure}()
26+
#1 %s(13): {closure}()
27+
#2 %s(14): {closure}()
28+
29+
#0 %s(13): {closure}()
30+
#1 %s(14): {closure}()
31+
32+
#0 %s(14): {closure}()

Zend/zend_builtin_functions.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,13 +1648,14 @@ ZEND_FUNCTION(debug_print_backtrace)
16481648
{
16491649
zend_long options = 0;
16501650
zend_long limit = 0;
1651+
zend_long skip_last = 1;
16511652
zval backtrace;
16521653

1653-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
1654+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|lll", &options, &limit, &skip_last) == FAILURE) {
16541655
RETURN_THROWS();
16551656
}
16561657

1657-
zend_fetch_debug_backtrace(&backtrace, 1, options, limit);
1658+
zend_fetch_debug_backtrace(&backtrace, skip_last, options, limit);
16581659
ZEND_ASSERT(Z_TYPE(backtrace) == IS_ARRAY);
16591660

16601661
zend_string *str = zend_trace_to_string(Z_ARRVAL(backtrace), /* include_main */ false);
@@ -1684,8 +1685,11 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
16841685
return;
16851686
}
16861687

1687-
if (skip_last) {
1688-
/* skip debug_backtrace() */
1688+
while (skip_last--) {
1689+
if (!call->prev_execute_data) {
1690+
break;
1691+
}
1692+
16891693
call = call->prev_execute_data;
16901694
}
16911695

@@ -1869,12 +1873,13 @@ ZEND_FUNCTION(debug_backtrace)
18691873
{
18701874
zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
18711875
zend_long limit = 0;
1876+
zend_long skip_last = 1;
18721877

1873-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
1878+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|lll", &options, &limit, &skip_last) == FAILURE) {
18741879
RETURN_THROWS();
18751880
}
18761881

1877-
zend_fetch_debug_backtrace(return_value, 1, options, limit);
1882+
zend_fetch_debug_backtrace(return_value, skip_last, options, limit);
18781883
}
18791884
/* }}} */
18801885

Zend/zend_builtin_functions.stub.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ function get_loaded_extensions(bool $zend_extensions = false): array {}
111111

112112
function get_defined_constants(bool $categorize = false): array {}
113113

114-
function debug_backtrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT, int $limit = 0): array {}
114+
function debug_backtrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT, int $limit = 0, int $skip_last = 1): array {}
115115

116-
function debug_print_backtrace(int $options = 0, int $limit = 0): void {}
116+
function debug_print_backtrace(int $options = 0, int $limit = 0, int $skip_last = 1): void {}
117117

118118
function extension_loaded(string $extension): bool {}
119119

Zend/zend_builtin_functions_arginfo.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: c333499e3ea100d976f0fa8bb8800ed21b04f1c6 */
2+
* Stub hash: 2db8f4b7a5b005a012e1d9d0d3aa2f26d0cb4f85 */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_version, 0, 0, IS_STRING, 0)
55
ZEND_END_ARG_INFO()
@@ -183,11 +183,13 @@ ZEND_END_ARG_INFO()
183183
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_debug_backtrace, 0, 0, IS_ARRAY, 0)
184184
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_LONG, 0, "DEBUG_BACKTRACE_PROVIDE_OBJECT")
185185
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "0")
186+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, skip_last, IS_LONG, 0, "1")
186187
ZEND_END_ARG_INFO()
187188

188189
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_debug_print_backtrace, 0, 0, IS_VOID, 0)
189190
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_LONG, 0, "0")
190191
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "0")
192+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, skip_last, IS_LONG, 0, "1")
191193
ZEND_END_ARG_INFO()
192194

193195
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_extension_loaded, 0, 1, _IS_BOOL, 0)

0 commit comments

Comments
 (0)