Skip to content

Commit 6d13252

Browse files
committed
Fix #74872 - Disambiguate the source of a trait alias where possible
1 parent 7bb696d commit 6d13252

File tree

10 files changed

+154
-13
lines changed

10 files changed

+154
-13
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ PHP NEWS
1010
. Fixed bug #74819 (wddx_deserialize() heap out-of-bound read via
1111
php_parse_date()). (Derick)
1212
. Fixed bug #74878 (Data race in ZTS builds). (Nikita)
13+
. Fixed bug #74872 (First Trait wins on importing same methods with diff
14+
alias). (pmmaga)
1315

1416
- EXIF:
1517
. Deprecated the read_exif_data() alias. (Kalle)

Zend/tests/traits/bug74872.phpt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
Bug #74872 (First Trait wins on importing same methods with diff alias)
3+
--FILE--
4+
<?php
5+
6+
trait Trait1
7+
{
8+
public function init()
9+
{
10+
echo("Trait1 - init\n");
11+
}
12+
}
13+
14+
trait Trait2
15+
{
16+
public function init()
17+
{
18+
echo("Trait2 - init\n");
19+
}
20+
}
21+
22+
class Test
23+
{
24+
use Trait1 {
25+
init as public method1trait1;
26+
}
27+
28+
use Trait2 {
29+
init as public method1trait2;
30+
}
31+
32+
final public function __construct()
33+
{
34+
$this->init();
35+
$this->method1trait1();
36+
$this->method1trait2();
37+
}
38+
39+
public function init()
40+
{
41+
echo("Test - init\n");
42+
}
43+
}
44+
45+
$test = new Test();
46+
47+
$reflection = new ReflectionClass( $test );
48+
49+
foreach($reflection->getTraitAliases() as $k => $v)
50+
{
51+
echo $k.' => '.$v."\n";
52+
}
53+
?>
54+
--EXPECT--
55+
Test - init
56+
Trait1 - init
57+
Trait2 - init
58+
method1trait1 => Trait1::init
59+
method1trait2 => Trait2::init

Zend/zend.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ typedef struct _zend_trait_alias {
110110
* modifiers to be set on trait method
111111
*/
112112
uint32_t modifiers;
113+
114+
/**
115+
* names of the traits for this alias
116+
*/
117+
zend_string **trait_names;
113118
} zend_trait_alias;
114119

115120
struct _zend_class_entry {

Zend/zend_compile.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6125,7 +6125,7 @@ static void zend_compile_trait_precedence(zend_ast *ast) /* {{{ */
61256125
}
61266126
/* }}} */
61276127

6128-
static void zend_compile_trait_alias(zend_ast *ast) /* {{{ */
6128+
static void zend_compile_trait_alias(zend_ast *ast, zend_ast *traits_ast) /* {{{ */
61296129
{
61306130
zend_ast *method_ref_ast = ast->child[0];
61316131
zend_ast *alias_ast = ast->child[1];
@@ -6144,6 +6144,11 @@ static void zend_compile_trait_alias(zend_ast *ast) /* {{{ */
61446144
alias = emalloc(sizeof(zend_trait_alias));
61456145
alias->trait_method = zend_compile_method_ref(method_ref_ast);
61466146
alias->modifiers = modifiers;
6147+
if (!alias->trait_method->class_name) {
6148+
alias->trait_names = zend_compile_name_list(traits_ast);
6149+
} else {
6150+
alias->trait_names = NULL;
6151+
}
61476152

61486153
if (alias_ast) {
61496154
alias->alias = zend_string_copy(zend_ast_get_str(alias_ast));
@@ -6202,7 +6207,7 @@ void zend_compile_use_trait(zend_ast *ast) /* {{{ */
62026207
zend_compile_trait_precedence(adaptation_ast);
62036208
break;
62046209
case ZEND_AST_TRAIT_ALIAS:
6205-
zend_compile_trait_alias(adaptation_ast);
6210+
zend_compile_trait_alias(adaptation_ast, ast->child[0]);
62066211
break;
62076212
EMPTY_SWITCH_DEFAULT_CASE()
62086213
}

Zend/zend_inheritance.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,7 @@ static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, ze
12401240
zend_string *lcname;
12411241
zend_function fn_copy;
12421242

1243-
/* apply aliases which are qualified with a class name, there should not be any ambiguity */
1243+
/* aliases which are qualified with a class name won't have any ambiguity. method names try to match with alias->trait_names */
12441244
if (ce->trait_aliases) {
12451245
alias_ptr = ce->trait_aliases;
12461246
alias = *alias_ptr;
@@ -1250,20 +1250,38 @@ static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, ze
12501250
&& (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
12511251
&& ZSTR_LEN(alias->trait_method->method_name) == ZSTR_LEN(fnname)
12521252
&& (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method->method_name), ZSTR_LEN(alias->trait_method->method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
1253-
fn_copy = *fn;
12541253

1255-
/* if it is 0, no modifieres has been changed */
1256-
if (alias->modifiers) {
1257-
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1254+
if (alias->trait_names) {
1255+
size_t i = 0;
1256+
while (alias->trait_names[i]) {
1257+
if (zend_binary_strcasecmp(
1258+
ZSTR_VAL(fn->common.scope->name),
1259+
ZSTR_LEN(fn->common.scope->name),
1260+
ZSTR_VAL(alias->trait_names[i]),
1261+
ZSTR_LEN(alias->trait_names[i])) == 0) {
1262+
1263+
alias->trait_method->class_name = alias->trait_names[i];
1264+
}
1265+
i++;
1266+
}
12581267
}
1268+
1269+
if (alias->trait_method->ce || alias->trait_method->class_name) {
1270+
fn_copy = *fn;
12591271

1260-
lcname = zend_string_tolower(alias->alias);
1261-
zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy, overriden);
1262-
zend_string_release(lcname);
1272+
/* if it is 0, no modifiers have been changed */
1273+
if (alias->modifiers) {
1274+
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1275+
}
12631276

1264-
/* Record the trait from which this alias was resolved. */
1265-
if (!alias->trait_method->ce) {
1266-
alias->trait_method->ce = fn->common.scope;
1277+
lcname = zend_string_tolower(alias->alias);
1278+
zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy, overriden);
1279+
zend_string_release(lcname);
1280+
1281+
/* Record the trait from which this alias was resolved. */
1282+
if (!alias->trait_method->ce) {
1283+
alias->trait_method->ce = fn->common.scope;
1284+
}
12671285
}
12681286
}
12691287
alias_ptr++;

Zend/zend_opcode.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,16 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce)
192192
zend_string_release(ce->trait_aliases[i]->alias);
193193
}
194194

195+
if (ce->trait_aliases[i]->trait_names) {
196+
size_t j = 0;
197+
while (ce->trait_aliases[i]->trait_names[j]) {
198+
zend_string_release(ce->trait_aliases[i]->trait_names[j]);
199+
j++;
200+
}
201+
202+
efree(ce->trait_aliases[i]->trait_names);
203+
}
204+
195205
efree(ce->trait_aliases[i]);
196206
i++;
197207
}

ext/opcache/zend_accelerator_util_funcs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
425425
memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
426426
trait_aliases[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
427427
memcpy(trait_aliases[i]->trait_method, ce->trait_aliases[i]->trait_method, sizeof(zend_trait_method_reference));
428+
trait_aliases[i]->trait_names = ce->trait_aliases[i]->trait_names;
428429
i++;
429430
}
430431
trait_aliases[i] = NULL;

ext/opcache/zend_file_cache.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,19 @@ static void zend_file_cache_serialize_class(zval *zv,
624624
}
625625
}
626626

627+
if (q->trait_names) {
628+
zend_string **r;
629+
630+
SERIALIZE_PTR(q->trait_names);
631+
r = q->trait_names;
632+
UNSERIALIZE_PTR(r);
633+
634+
while (*r) {
635+
SERIALIZE_STR(*r);
636+
r++;
637+
}
638+
}
639+
627640
if (q->alias) {
628641
SERIALIZE_STR(q->alias);
629642
}
@@ -1210,6 +1223,18 @@ static void zend_file_cache_unserialize_class(zval *zv,
12101223
}
12111224
}
12121225

1226+
if (q->trait_names) {
1227+
zend_string **r;
1228+
1229+
UNSERIALIZE_PTR(q->trait_names);
1230+
r = q->trait_names;
1231+
1232+
while (*r) {
1233+
UNSERIALIZE_STR(*r);
1234+
r++;
1235+
}
1236+
}
1237+
12131238
if (q->alias) {
12141239
UNSERIALIZE_STR(q->alias);
12151240
}

ext/opcache/zend_persist.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,14 @@ static void zend_persist_class_entry(zval *zv)
722722
sizeof(zend_trait_method_reference));
723723
}
724724

725+
if (ce->trait_aliases[i]->trait_names) {
726+
int j = 0;
727+
while (ce->trait_aliases[i]->trait_names[j]) {
728+
zend_accel_store_interned_string(ce->trait_aliases[i]->trait_names[j]);
729+
j++;
730+
}
731+
}
732+
725733
if (ce->trait_aliases[i]->alias) {
726734
zend_accel_store_interned_string(ce->trait_aliases[i]->alias);
727735
}

ext/opcache/zend_persist_calc.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,14 @@ static void zend_persist_class_entry_calc(zval *zv)
356356
ADD_SIZE(sizeof(zend_trait_method_reference));
357357
}
358358

359+
if (ce->trait_aliases[i]->trait_names) {
360+
int j = 0;
361+
while (ce->trait_aliases[i]->trait_names[j]) {
362+
ADD_INTERNED_STRING(ce->trait_aliases[i]->trait_names[j], 0);
363+
j++;
364+
}
365+
}
366+
359367
if (ce->trait_aliases[i]->alias) {
360368
ADD_INTERNED_STRING(ce->trait_aliases[i]->alias, 0);
361369
}

0 commit comments

Comments
 (0)