Skip to content

Commit 7dce019

Browse files
committed
Fixed bug #64239 (Debug backtrace changed behavior since 5.4.10 or 5.4.11)
1 parent 08624ea commit 7dce019

File tree

8 files changed

+216
-13
lines changed

8 files changed

+216
-13
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ PHP NEWS
77
(Dmitry)
88
. Fixed bug #64370 (microtime(true) less than $_SERVER['REQUEST_TIME_FLOAT']).
99
(Anatol)
10+
. Fixed bug #64239 (Debug backtrace changed behavior since 5.4.10 or 5.4.11).
11+
(Dmitry, Laruence)
1012
. Fixed bug #63976 (Parent class incorrectly using child constant in class
1113
property). (Dmitry)
1214
. Fixed bug #62343 (Show class_alias In get_declared_classes()) (Dmitry)

Zend/tests/bug64239_1.phpt

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,26 @@ Bug #64239 (get_class_methods() changed behavior)
33
--FILE--
44
<?php
55
class A {
6-
public function test() { $this->backtrace(); }
7-
}
8-
class B {
96
use T2 { t2method as Bmethod; }
107
}
8+
9+
class B extends A {
10+
}
11+
1112
trait T2 {
1213
public function t2method() {
1314
}
1415
}
15-
var_dump(get_class_methods("B"));
16+
print_r(get_class_methods("A"));
17+
print_r(get_class_methods("B"));
1618
--EXPECT--
17-
array(2) {
18-
[0]=>
19-
string(7) "bmethod"
20-
[1]=>
21-
string(8) "t2method"
22-
}
19+
Array
20+
(
21+
[0] => Bmethod
22+
[1] => t2method
23+
)
24+
Array
25+
(
26+
[0] => Bmethod
27+
[1] => t2method
28+
)

Zend/tests/bug64239_2.phpt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Bug #64239 (debug_backtrace() changed behavior)
3+
--FILE--
4+
<?php
5+
class A {
6+
use T1;
7+
public function test() { $this->backtrace(); }
8+
}
9+
10+
class B {
11+
use T2 { t2method as Bmethod; }
12+
}
13+
14+
class C extends A {
15+
}
16+
17+
trait T1 {
18+
protected function backtrace() {
19+
$b = new B();
20+
$b->Bmethod();
21+
}
22+
}
23+
trait T2 {
24+
public function t2method() {
25+
print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1));
26+
}
27+
}
28+
$a = new A();
29+
$a->test();
30+
31+
$c = new C();
32+
$c->test();
33+
?>
34+
--EXPECTF--
35+
Array
36+
(
37+
[0] => Array
38+
(
39+
[file] => %sbug64239_2.php
40+
[line] => %d
41+
[function] => Bmethod
42+
[class] => B
43+
[type] => ->
44+
)
45+
46+
)
47+
Array
48+
(
49+
[0] => Array
50+
(
51+
[file] => %sbug64239_2.php
52+
[line] => %d
53+
[function] => Bmethod
54+
[class] => B
55+
[type] => ->
56+
)
57+
58+
)

Zend/tests/bug64239_3.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Bug #64239 (debug_print_backtrace() changed behavior)
3+
--FILE--
4+
<?php
5+
class A {
6+
use T2 { t2method as Bmethod; }
7+
}
8+
9+
class C extends A {
10+
public function Bmethod() {
11+
debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
12+
}
13+
}
14+
15+
trait T2 {
16+
public function t2method() {
17+
debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
18+
}
19+
}
20+
21+
$a = new A();
22+
$a->Bmethod();
23+
$a->t2method();
24+
25+
$c = new C();
26+
$c->Bmethod();
27+
$c->t2method();
28+
?>
29+
--EXPECTF--
30+
#0 A->Bmethod() called at [%sbug64239_3.php:%d]
31+
#0 A->t2method() called at [%sbug64239_3.php:%d]
32+
#0 C->Bmethod() called at [%sbug64239_3.php:%d]
33+
#0 A->t2method() called at [%sbug64239_3.php:%d]

Zend/tests/bug64239_4.phpt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
Bug #64239 (debug_print_backtrace() changed behavior)
3+
--FILE--
4+
<?php
5+
class A {
6+
use T2 { t2method as Bmethod; }
7+
}
8+
9+
class C extends A {
10+
public static function Bmethod() {
11+
debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
12+
}
13+
}
14+
15+
trait T2 {
16+
public static function t2method() {
17+
debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
18+
}
19+
}
20+
21+
A::Bmethod();
22+
A::t2method();
23+
24+
C::Bmethod();
25+
C::t2method();
26+
?>
27+
--EXPECTF--
28+
#0 A::Bmethod() called at [%sbug64239_4.php:%d]
29+
#0 A::t2method() called at [%sbug64239_4.php:%d]
30+
#0 C::Bmethod() called at [%sbug64239_4.php:%d]
31+
#0 A::t2method() called at [%sbug64239_4.php:%d]

Zend/zend_API.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3913,6 +3913,62 @@ ZEND_API void zend_restore_error_handling(zend_error_handling *saved TSRMLS_DC)
39133913
}
39143914
/* }}} */
39153915

3916+
ZEND_API const char* zend_find_alias_name(zend_class_entry *ce, const char *name, zend_uint len) /* {{{ */
3917+
{
3918+
zend_trait_alias *alias, **alias_ptr;
3919+
3920+
alias_ptr = ce->trait_aliases;
3921+
alias = *alias_ptr;
3922+
while (alias) {
3923+
if (alias->alias_len == len &&
3924+
!strncasecmp(name, alias->alias, alias->alias_len)) {
3925+
return alias->alias;
3926+
}
3927+
alias_ptr++;
3928+
alias = *alias_ptr;
3929+
}
3930+
3931+
return name;
3932+
}
3933+
/* }}} */
3934+
3935+
ZEND_API const char* zend_resolve_method_name(zend_class_entry *ce, zend_function *f) /* {{{ */
3936+
{
3937+
zend_function *func;
3938+
HashPosition iterator;
3939+
HashTable *function_table;
3940+
3941+
if (f->common.type != ZEND_USER_FUNCTION ||
3942+
*(f->op_array.refcount) < 2 ||
3943+
!f->common.scope ||
3944+
!f->common.scope->trait_aliases) {
3945+
return f->common.function_name;
3946+
}
3947+
3948+
function_table = &ce->function_table;
3949+
zend_hash_internal_pointer_reset_ex(function_table, &iterator);
3950+
while (zend_hash_get_current_data_ex(function_table, (void **)&func, &iterator) == SUCCESS) {
3951+
if (func == f) {
3952+
char *name;
3953+
uint len;
3954+
ulong idx;
3955+
3956+
if (zend_hash_get_current_key_ex(function_table, &name, &len, &idx, 0, &iterator) != HASH_KEY_IS_STRING) {
3957+
return f->common.function_name;
3958+
}
3959+
--len;
3960+
if (len == strlen(f->common.function_name) &&
3961+
!strncasecmp(name, f->common.function_name, len)) {
3962+
return f->common.function_name;
3963+
}
3964+
return zend_find_alias_name(f->common.scope, name, len);
3965+
}
3966+
zend_hash_move_forward_ex(function_table, &iterator);
3967+
}
3968+
return f->common.function_name;
3969+
}
3970+
/* }}} */
3971+
39163972
/*
39173973
* Local variables:
39183974
* tab-width: 4

Zend/zend_API.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,9 @@ ZEND_API void zend_reset_all_cv(HashTable *symbol_table TSRMLS_DC);
517517

518518
ZEND_API void zend_rebuild_symbol_table(TSRMLS_D);
519519

520+
ZEND_API const char* zend_find_alias_name(zend_class_entry *ce, const char *name, zend_uint len);
521+
ZEND_API const char* zend_resolve_method_name(zend_class_entry *ce, zend_function *f);
522+
520523
#define add_method(arg, key, method) add_assoc_function((arg), (key), (method))
521524

522525
ZEND_API ZEND_FUNCTION(display_disabled_function);

Zend/zend_builtin_functions.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ ZEND_FUNCTION(get_class_methods)
10921092
(len != key_len - 1 ||
10931093
!same_name(key, mptr->common.function_name, len))) {
10941094
MAKE_STD_ZVAL(method_name);
1095-
ZVAL_STRINGL(method_name, key, key_len - 1, 1);
1095+
ZVAL_STRINGL(method_name, zend_find_alias_name(mptr->common.scope, key, key_len - 1), key_len - 1, 1);
10961096
zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL);
10971097
} else {
10981098
MAKE_STD_ZVAL(method_name);
@@ -2118,7 +2118,14 @@ ZEND_FUNCTION(debug_print_backtrace)
21182118
lineno = 0;
21192119
}
21202120

2121-
function_name = ptr->function_state.function->common.function_name;
2121+
function_name = (ptr->function_state.function->common.scope &&
2122+
ptr->function_state.function->common.scope->trait_aliases) ?
2123+
zend_resolve_method_name(
2124+
ptr->object ?
2125+
Z_OBJCE_P(ptr->object) :
2126+
ptr->function_state.function->common.scope,
2127+
ptr->function_state.function) :
2128+
ptr->function_state.function->common.function_name;
21222129

21232130
if (function_name) {
21242131
if (ptr->object) {
@@ -2299,7 +2306,14 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
22992306
filename = NULL;
23002307
}
23012308

2302-
function_name = ptr->function_state.function->common.function_name;
2309+
function_name = (ptr->function_state.function->common.scope &&
2310+
ptr->function_state.function->common.scope->trait_aliases) ?
2311+
zend_resolve_method_name(
2312+
ptr->object ?
2313+
Z_OBJCE_P(ptr->object) :
2314+
ptr->function_state.function->common.scope,
2315+
ptr->function_state.function) :
2316+
ptr->function_state.function->common.function_name;
23032317

23042318
if (function_name) {
23052319
add_assoc_string_ex(stack_frame, "function", sizeof("function"), (char*)function_name, 1);

0 commit comments

Comments
 (0)