29
29
30
30
static void add_dependency_obligation (zend_class_entry * ce , zend_class_entry * dependency_ce );
31
31
static void add_compatibility_obligation (
32
- zend_class_entry * ce , const zend_function * child_fn , const zend_function * parent_fn );
32
+ zend_class_entry * ce , const zend_function * child_fn , const zend_function * parent_fn ,
33
+ zend_class_entry * parent_scope );
33
34
static void add_property_compatibility_obligation (
34
35
zend_class_entry * ce , const zend_property_info * child_prop ,
35
36
const zend_property_info * parent_prop );
@@ -496,8 +497,8 @@ static inheritance_status zend_perform_covariant_type_check(
496
497
/* }}} */
497
498
498
499
static inheritance_status zend_do_perform_arg_type_hint_check (
499
- const zend_function * fe , zend_arg_info * fe_arg_info ,
500
- const zend_function * proto , zend_arg_info * proto_arg_info ) /* {{{ */
500
+ zend_class_entry * fe_scope , zend_arg_info * fe_arg_info ,
501
+ zend_class_entry * proto_scope , zend_arg_info * proto_arg_info ) /* {{{ */
501
502
{
502
503
if (!ZEND_TYPE_IS_SET (fe_arg_info -> type )) {
503
504
/* Child with no type is always compatible */
@@ -512,12 +513,16 @@ static inheritance_status zend_do_perform_arg_type_hint_check(
512
513
/* Contravariant type check is performed as a covariant type check with swapped
513
514
* argument order. */
514
515
return zend_perform_covariant_type_check (
515
- proto -> common . scope , proto_arg_info -> type , fe -> common . scope , fe_arg_info -> type );
516
+ proto_scope , proto_arg_info -> type , fe_scope , fe_arg_info -> type );
516
517
}
517
518
/* }}} */
518
519
520
+ /* For abstract trait methods, proto_scope will differ from proto->common.scope,
521
+ * as self will refer to the self of the class the trait is used in, not the trait
522
+ * the method was declared in. */
519
523
static inheritance_status zend_do_perform_implementation_check (
520
- const zend_function * fe , const zend_function * proto ) /* {{{ */
524
+ const zend_function * fe , const zend_function * proto ,
525
+ zend_class_entry * proto_scope ) /* {{{ */
521
526
{
522
527
uint32_t i , num_args , proto_num_args , fe_num_args ;
523
528
inheritance_status status , local_status ;
@@ -578,7 +583,8 @@ static inheritance_status zend_do_perform_implementation_check(
578
583
return INHERITANCE_ERROR ;
579
584
}
580
585
581
- local_status = zend_do_perform_arg_type_hint_check (fe , fe_arg_info , proto , proto_arg_info );
586
+ local_status = zend_do_perform_arg_type_hint_check (
587
+ fe -> common .scope , fe_arg_info , proto_scope , proto_arg_info );
582
588
583
589
if (UNEXPECTED (local_status != INHERITANCE_SUCCESS )) {
584
590
if (UNEXPECTED (local_status == INHERITANCE_ERROR )) {
@@ -604,7 +610,7 @@ static inheritance_status zend_do_perform_implementation_check(
604
610
605
611
local_status = zend_perform_covariant_type_check (
606
612
fe -> common .scope , fe -> common .arg_info [-1 ].type ,
607
- proto -> common . scope , proto -> common .arg_info [-1 ].type );
613
+ proto_scope , proto -> common .arg_info [-1 ].type );
608
614
609
615
if (UNEXPECTED (local_status != INHERITANCE_SUCCESS )) {
610
616
if (UNEXPECTED (local_status == INHERITANCE_ERROR )) {
@@ -619,10 +625,11 @@ static inheritance_status zend_do_perform_implementation_check(
619
625
}
620
626
/* }}} */
621
627
622
- static ZEND_COLD void zend_append_type_hint (smart_str * str , const zend_function * fptr , zend_arg_info * arg_info , int return_hint ) /* {{{ */
628
+ static ZEND_COLD void zend_append_type_hint (
629
+ smart_str * str , zend_class_entry * scope , zend_arg_info * arg_info , int return_hint ) /* {{{ */
623
630
{
624
631
if (ZEND_TYPE_IS_SET (arg_info -> type )) {
625
- zend_string * type_str = zend_type_to_string_resolved (arg_info -> type , fptr -> common . scope );
632
+ zend_string * type_str = zend_type_to_string_resolved (arg_info -> type , scope );
626
633
smart_str_append (str , type_str );
627
634
zend_string_release (type_str );
628
635
if (!return_hint ) {
@@ -632,7 +639,8 @@ static ZEND_COLD void zend_append_type_hint(smart_str *str, const zend_function
632
639
}
633
640
/* }}} */
634
641
635
- static ZEND_COLD zend_string * zend_get_function_declaration (const zend_function * fptr ) /* {{{ */
642
+ static ZEND_COLD zend_string * zend_get_function_declaration (
643
+ const zend_function * fptr , zend_class_entry * scope ) /* {{{ */
636
644
{
637
645
smart_str str = {0 };
638
646
@@ -659,7 +667,7 @@ static ZEND_COLD zend_string *zend_get_function_declaration(const zend_function
659
667
num_args ++ ;
660
668
}
661
669
for (i = 0 ; i < num_args ;) {
662
- zend_append_type_hint (& str , fptr , arg_info , 0 );
670
+ zend_append_type_hint (& str , scope , arg_info , 0 );
663
671
664
672
if (ZEND_ARG_SEND_MODE (arg_info )) {
665
673
smart_str_appendc (& str , '&' );
@@ -752,7 +760,7 @@ static ZEND_COLD zend_string *zend_get_function_declaration(const zend_function
752
760
753
761
if (fptr -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) {
754
762
smart_str_appends (& str , ": " );
755
- zend_append_type_hint (& str , fptr , fptr -> common .arg_info - 1 , 1 );
763
+ zend_append_type_hint (& str , scope , fptr -> common .arg_info - 1 , 1 );
756
764
}
757
765
smart_str_0 (& str );
758
766
@@ -765,10 +773,10 @@ static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
765
773
}
766
774
767
775
static void ZEND_COLD emit_incompatible_method_error (
768
- const zend_function * child , const zend_function * parent ,
776
+ const zend_function * child , const zend_function * parent , zend_class_entry * parent_scope ,
769
777
inheritance_status status ) {
770
- zend_string * parent_prototype = zend_get_function_declaration (parent );
771
- zend_string * child_prototype = zend_get_function_declaration (child );
778
+ zend_string * parent_prototype = zend_get_function_declaration (parent , parent_scope );
779
+ zend_string * child_prototype = zend_get_function_declaration (child , child -> common . scope );
772
780
if (status == INHERITANCE_UNRESOLVED ) {
773
781
/* Fetch the first unresolved class from registered autoloads */
774
782
zend_string * unresolved_class = NULL ;
@@ -791,20 +799,23 @@ static void ZEND_COLD emit_incompatible_method_error(
791
799
792
800
static void perform_delayable_implementation_check (
793
801
zend_class_entry * ce , const zend_function * fe ,
794
- const zend_function * proto )
802
+ const zend_function * proto , zend_class_entry * proto_scope )
795
803
{
796
- inheritance_status status = zend_do_perform_implementation_check (fe , proto );
804
+ inheritance_status status = zend_do_perform_implementation_check (fe , proto , proto_scope );
797
805
if (UNEXPECTED (status != INHERITANCE_SUCCESS )) {
798
806
if (EXPECTED (status == INHERITANCE_UNRESOLVED )) {
799
- add_compatibility_obligation (ce , fe , proto );
807
+ add_compatibility_obligation (ce , fe , proto , proto_scope );
800
808
} else {
801
809
ZEND_ASSERT (status == INHERITANCE_ERROR );
802
- emit_incompatible_method_error (fe , proto , status );
810
+ emit_incompatible_method_error (fe , proto , proto_scope , status );
803
811
}
804
812
}
805
813
}
806
814
807
- static zend_always_inline inheritance_status do_inheritance_check_on_method_ex (zend_function * child , zend_function * parent , zend_class_entry * ce , zval * child_zv , zend_bool check_visibility , zend_bool check_only , zend_bool checked ) /* {{{ */
815
+ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex (
816
+ zend_function * child , zend_function * parent ,
817
+ zend_class_entry * ce , zend_class_entry * parent_scope , zval * child_zv ,
818
+ zend_bool check_visibility , zend_bool check_only , zend_bool checked ) /* {{{ */
808
819
{
809
820
uint32_t child_flags ;
810
821
uint32_t parent_flags = parent -> common .fn_flags ;
@@ -899,17 +910,20 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(z
899
910
900
911
if (!checked ) {
901
912
if (check_only ) {
902
- return zend_do_perform_implementation_check (child , parent );
913
+ return zend_do_perform_implementation_check (child , parent , parent_scope );
903
914
}
904
- perform_delayable_implementation_check (ce , child , parent );
915
+ perform_delayable_implementation_check (ce , child , parent , parent_scope );
905
916
}
906
917
return INHERITANCE_SUCCESS ;
907
918
}
908
919
/* }}} */
909
920
910
- static zend_never_inline void do_inheritance_check_on_method (zend_function * child , zend_function * parent , zend_class_entry * ce , zval * child_zv , zend_bool check_visibility ) /* {{{ */
921
+ static zend_never_inline void do_inheritance_check_on_method (
922
+ zend_function * child , zend_function * parent ,
923
+ zend_class_entry * ce , zend_class_entry * parent_scope ,
924
+ zval * child_zv , zend_bool check_visibility ) /* {{{ */
911
925
{
912
- do_inheritance_check_on_method_ex (child , parent , ce , child_zv , check_visibility , 0 , 0 );
926
+ do_inheritance_check_on_method_ex (child , parent , ce , parent_scope , child_zv , check_visibility , 0 , 0 );
913
927
}
914
928
/* }}} */
915
929
@@ -927,9 +941,11 @@ static zend_always_inline void do_inherit_method(zend_string *key, zend_function
927
941
928
942
if (checked ) {
929
943
do_inheritance_check_on_method_ex (
930
- func , parent , ce , child , /* check_visibility */ 1 , 0 , checked );
944
+ func , parent , ce , parent -> common .scope , child ,
945
+ /* check_visibility */ 1 , 0 , checked );
931
946
} else {
932
- do_inheritance_check_on_method (func , parent , ce , child , /* check_visibility */ 1 );
947
+ do_inheritance_check_on_method (
948
+ func , parent , ce , parent -> common .scope , child , /* check_visibility */ 1 );
933
949
}
934
950
} else {
935
951
@@ -1589,8 +1605,13 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
1589
1605
/* "abstract private" methods in traits were not available prior to PHP 8.
1590
1606
* As such, "abstract protected" was sometimes used to indicate trait requirements,
1591
1607
* even though the "implementing" method was private. Do not check visibility
1592
- * requirements to maintain backwards-compatibility with such usage. */
1593
- do_inheritance_check_on_method (existing_fn , fn , ce , NULL , /* check_visibility */ 0 );
1608
+ * requirements to maintain backwards-compatibility with such usage.
1609
+ *
1610
+ * The parent_scope passed here is not fn->common.scope, because we want "self" to be
1611
+ * resolved against the using class, not the declaring trait.
1612
+ */
1613
+ do_inheritance_check_on_method (
1614
+ existing_fn , fn , ce , /* parent_scope */ ce , NULL , /* check_visibility */ 0 );
1594
1615
return ;
1595
1616
}
1596
1617
@@ -1607,7 +1628,8 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
1607
1628
} else {
1608
1629
/* inherited members are overridden by members inserted by traits */
1609
1630
/* check whether the trait method fulfills the inheritance requirements */
1610
- do_inheritance_check_on_method (fn , existing_fn , ce , NULL , /* check_visibility */ 1 );
1631
+ do_inheritance_check_on_method (
1632
+ fn , existing_fn , ce , existing_fn -> common .scope , NULL , /* check_visibility */ 1 );
1611
1633
}
1612
1634
}
1613
1635
@@ -2182,6 +2204,7 @@ typedef struct {
2182
2204
* so use copies of functions here as well. */
2183
2205
zend_function parent_fn ;
2184
2206
zend_function child_fn ;
2207
+ zend_class_entry * parent_scope ;
2185
2208
};
2186
2209
struct {
2187
2210
const zend_property_info * parent_prop ;
@@ -2229,7 +2252,8 @@ static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *de
2229
2252
}
2230
2253
2231
2254
static void add_compatibility_obligation (
2232
- zend_class_entry * ce , const zend_function * child_fn , const zend_function * parent_fn ) {
2255
+ zend_class_entry * ce , const zend_function * child_fn , const zend_function * parent_fn ,
2256
+ zend_class_entry * parent_scope ) {
2233
2257
HashTable * obligations = get_or_init_obligations_for_class (ce );
2234
2258
variance_obligation * obligation = emalloc (sizeof (variance_obligation ));
2235
2259
obligation -> type = OBLIGATION_COMPATIBILITY ;
@@ -2244,6 +2268,7 @@ static void add_compatibility_obligation(
2244
2268
} else {
2245
2269
memcpy (& obligation -> parent_fn , parent_fn , sizeof (zend_op_array ));
2246
2270
}
2271
+ obligation -> parent_scope = parent_scope ;
2247
2272
zend_hash_next_index_insert_ptr (obligations , obligation );
2248
2273
}
2249
2274
@@ -2272,13 +2297,14 @@ static int check_variance_obligation(zval *zv) {
2272
2297
}
2273
2298
} else if (obligation -> type == OBLIGATION_COMPATIBILITY ) {
2274
2299
inheritance_status status = zend_do_perform_implementation_check (
2275
- & obligation -> child_fn , & obligation -> parent_fn );
2300
+ & obligation -> child_fn , & obligation -> parent_fn , obligation -> parent_scope );
2276
2301
if (UNEXPECTED (status != INHERITANCE_SUCCESS )) {
2277
2302
if (EXPECTED (status == INHERITANCE_UNRESOLVED )) {
2278
2303
return ZEND_HASH_APPLY_KEEP ;
2279
2304
}
2280
2305
ZEND_ASSERT (status == INHERITANCE_ERROR );
2281
- emit_incompatible_method_error (& obligation -> child_fn , & obligation -> parent_fn , status );
2306
+ emit_incompatible_method_error (
2307
+ & obligation -> child_fn , & obligation -> parent_fn , obligation -> parent_scope , status );
2282
2308
}
2283
2309
/* Either the compatibility check was successful or only threw a warning. */
2284
2310
} else {
@@ -2345,10 +2371,10 @@ static void report_variance_errors(zend_class_entry *ce) {
2345
2371
/* Just used to populate the delayed_autoloads table,
2346
2372
* which will be used when printing the "unresolved" error. */
2347
2373
inheritance_status status = zend_do_perform_implementation_check (
2348
- & obligation -> child_fn , & obligation -> parent_fn );
2374
+ & obligation -> child_fn , & obligation -> parent_fn , obligation -> parent_scope );
2349
2375
ZEND_ASSERT (status == INHERITANCE_UNRESOLVED );
2350
2376
emit_incompatible_method_error (
2351
- & obligation -> child_fn , & obligation -> parent_fn , status );
2377
+ & obligation -> child_fn , & obligation -> parent_fn , obligation -> parent_scope , status );
2352
2378
} else if (obligation -> type == OBLIGATION_PROPERTY_COMPATIBILITY ) {
2353
2379
emit_incompatible_property_error (obligation -> child_prop , obligation -> parent_prop );
2354
2380
} else {
@@ -2475,7 +2501,8 @@ static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_e
2475
2501
zend_function * child_func = Z_FUNC_P (zv );
2476
2502
inheritance_status status =
2477
2503
do_inheritance_check_on_method_ex (
2478
- child_func , parent_func , ce , NULL , /* check_visibility */ 1 , 1 , 0 );
2504
+ child_func , parent_func , ce , parent_func -> common .scope , NULL ,
2505
+ /* check_visibility */ 1 , 1 , 0 );
2479
2506
2480
2507
if (UNEXPECTED (status != INHERITANCE_SUCCESS )) {
2481
2508
return status ;
0 commit comments