@@ -3664,51 +3664,95 @@ static void preload_sort_classes(void *base, size_t count, size_t siz, compare_f
3664
3664
}
3665
3665
}
3666
3666
3667
- static bool preload_needed_types_known (zend_class_entry * ce );
3668
- static void get_unlinked_dependency (zend_class_entry * ce , const char * * kind , const char * * name ) {
3669
- zend_class_entry * p ;
3670
- * kind = "Unknown reason" ;
3671
- * name = "" ;
3667
+ typedef struct {
3668
+ zend_class_entry * parent ;
3669
+ zend_class_entry * * interfaces ;
3670
+ zend_class_entry * * traits ;
3671
+ const char * error_kind ;
3672
+ const char * error_name ;
3673
+ void * checkpoint ;
3674
+ } preload_deps ;
3675
+
3676
+ static bool preload_needed_types_known (const preload_deps * deps , zend_class_entry * ce );
3677
+ static zend_result preload_resolve_deps (preload_deps * deps , zend_class_entry * ce )
3678
+ {
3679
+ memset (deps , 0 , sizeof (preload_deps ));
3680
+ deps -> checkpoint = zend_arena_checkpoint (CG (arena ));
3672
3681
3673
3682
if (ce -> parent_name ) {
3674
3683
zend_string * key = zend_string_tolower (ce -> parent_name );
3675
- p = zend_hash_find_ptr (EG (class_table ), key );
3684
+ deps -> parent = zend_hash_find_ptr (EG (class_table ), key );
3676
3685
zend_string_release (key );
3677
- if (!p ) {
3678
- * kind = "Unknown parent " ;
3679
- * name = ZSTR_VAL (ce -> parent_name );
3680
- return ;
3686
+ if (!deps -> parent ) {
3687
+ deps -> error_kind = "Unknown parent " ;
3688
+ deps -> error_name = ZSTR_VAL (ce -> parent_name );
3689
+ return FAILURE ;
3681
3690
}
3682
3691
}
3683
3692
3684
3693
if (ce -> num_interfaces ) {
3685
- uint32_t i ;
3686
- for (i = 0 ; i < ce -> num_interfaces ; i ++ ) {
3687
- p = zend_hash_find_ptr (EG (class_table ), ce -> interface_names [i ].lc_name );
3688
- if (!p ) {
3689
- * kind = "Unknown interface " ;
3690
- * name = ZSTR_VAL (ce -> interface_names [i ].name );
3691
- return ;
3694
+ deps -> interfaces =
3695
+ zend_arena_alloc (& CG (arena ), ce -> num_interfaces * sizeof (zend_class_entry ));
3696
+ for (uint32_t i = 0 ; i < ce -> num_interfaces ; i ++ ) {
3697
+ deps -> interfaces [i ] =
3698
+ zend_hash_find_ptr (EG (class_table ), ce -> interface_names [i ].lc_name );
3699
+ if (!deps -> interfaces [i ]) {
3700
+ deps -> error_kind = "Unknown interface " ;
3701
+ deps -> error_name = ZSTR_VAL (ce -> interface_names [i ].name );
3702
+ return FAILURE ;
3692
3703
}
3693
3704
}
3694
3705
}
3695
3706
3696
3707
if (ce -> num_traits ) {
3697
- uint32_t i ;
3698
- for (i = 0 ; i < ce -> num_traits ; i ++ ) {
3699
- p = zend_hash_find_ptr (EG (class_table ), ce -> trait_names [i ].lc_name );
3700
- if (!p ) {
3701
- * kind = "Unknown trait " ;
3702
- * name = ZSTR_VAL (ce -> trait_names [i ].name );
3703
- return ;
3708
+ deps -> traits =
3709
+ zend_arena_alloc (& CG (arena ), ce -> num_traits * sizeof (zend_class_entry ));
3710
+ for (uint32_t i = 0 ; i < ce -> num_traits ; i ++ ) {
3711
+ deps -> traits [i ] = zend_hash_find_ptr (EG (class_table ), ce -> trait_names [i ].lc_name );
3712
+ if (!deps -> traits [i ]) {
3713
+ deps -> error_kind = "Unknown trait " ;
3714
+ deps -> error_name = ZSTR_VAL (ce -> trait_names [i ].name );
3715
+ return FAILURE ;
3704
3716
}
3705
3717
}
3706
3718
}
3707
3719
3708
- if (!preload_needed_types_known (ce )) {
3709
- * kind = "Unknown type dependencies" ;
3710
- return ;
3720
+ /* TODO: This is much more restrictive than necessary. We only need to actually
3721
+ * know the types for covariant checks, but don't need them if we can ensure
3722
+ * compatibility through a simple string comparison. We could improve this using
3723
+ * a more general version of zend_can_early_bind(). */
3724
+ if (!preload_needed_types_known (deps , ce )) {
3725
+ deps -> error_kind = "Unknown type dependencies" ;
3726
+ deps -> error_name = "" ;
3727
+ return FAILURE ;
3728
+ }
3729
+
3730
+ return SUCCESS ;
3731
+ }
3732
+
3733
+ static void preload_release_deps (preload_deps * deps )
3734
+ {
3735
+ zend_arena_release (& CG (arena ), deps -> checkpoint );
3736
+ }
3737
+
3738
+ static bool preload_can_resolve_deps (zend_class_entry * ce )
3739
+ {
3740
+ preload_deps deps ;
3741
+ zend_result result = preload_resolve_deps (& deps , ce );
3742
+ preload_release_deps (& deps );
3743
+ return result == SUCCESS ;
3744
+ }
3745
+
3746
+ static void get_unlinked_dependency (zend_class_entry * ce , const char * * kind , const char * * name ) {
3747
+ preload_deps deps ;
3748
+ if (preload_resolve_deps (& deps , ce ) == FAILURE ) {
3749
+ * kind = deps .error_kind ;
3750
+ * name = deps .error_name ;
3751
+ } else {
3752
+ * kind = "Unknown reason" ;
3753
+ * name = "" ;
3711
3754
}
3755
+ preload_release_deps (& deps );
3712
3756
}
3713
3757
3714
3758
static zend_result preload_update_constant (zval * val , zend_class_entry * scope )
@@ -3844,58 +3888,51 @@ static bool preload_is_type_known(zend_class_entry *ce, zend_type *type) {
3844
3888
return 1 ;
3845
3889
}
3846
3890
3847
- static bool preload_is_method_maybe_override (zend_class_entry * ce , zend_string * lcname ) {
3848
- zend_class_entry * p ;
3891
+ static bool preload_is_method_maybe_override (
3892
+ const preload_deps * deps , zend_class_entry * ce , zend_string * lcname ) {
3849
3893
if (ce -> trait_aliases || ce -> trait_precedences ) {
3850
- return 1 ;
3894
+ return true ;
3851
3895
}
3852
3896
3853
3897
if (ce -> parent_name ) {
3854
- zend_string * key = zend_string_tolower (ce -> parent_name );
3855
- p = zend_hash_find_ptr (EG (class_table ), key );
3856
- zend_string_release (key );
3857
- if (zend_hash_exists (& p -> function_table , lcname )) {
3858
- return 1 ;
3898
+ if (zend_hash_exists (& deps -> parent -> function_table , lcname )) {
3899
+ return true;
3859
3900
}
3860
3901
}
3861
3902
3862
3903
if (ce -> num_interfaces ) {
3863
- uint32_t i ;
3864
- for (i = 0 ; i < ce -> num_interfaces ; i ++ ) {
3865
- zend_class_entry * p = zend_hash_find_ptr (EG (class_table ), ce -> interface_names [i ].lc_name );
3866
- if (zend_hash_exists (& p -> function_table , lcname )) {
3867
- return 1 ;
3904
+ for (uint32_t i = 0 ; i < ce -> num_interfaces ; i ++ ) {
3905
+ if (zend_hash_exists (& deps -> interfaces [i ]-> function_table , lcname )) {
3906
+ return true;
3868
3907
}
3869
3908
}
3870
3909
}
3871
3910
3872
3911
if (ce -> num_traits ) {
3873
- uint32_t i ;
3874
- for (i = 0 ; i < ce -> num_traits ; i ++ ) {
3875
- zend_class_entry * p = zend_hash_find_ptr (EG (class_table ), ce -> trait_names [i ].lc_name );
3876
- if (zend_hash_exists (& p -> function_table , lcname )) {
3877
- return 1 ;
3912
+ for (uint32_t i = 0 ; i < ce -> num_traits ; i ++ ) {
3913
+ if (zend_hash_exists (& deps -> traits [i ]-> function_table , lcname )) {
3914
+ return true;
3878
3915
}
3879
3916
}
3880
3917
}
3881
3918
3882
- return 0 ;
3919
+ return false ;
3883
3920
}
3884
3921
3885
- static bool preload_needed_types_known (zend_class_entry * ce ) {
3922
+ static bool preload_needed_types_known (const preload_deps * deps , zend_class_entry * ce ) {
3886
3923
zend_function * fptr ;
3887
3924
zend_string * lcname ;
3888
3925
ZEND_HASH_FOREACH_STR_KEY_PTR (& ce -> function_table , lcname , fptr ) {
3889
3926
uint32_t i ;
3890
3927
if (fptr -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) {
3891
3928
if (!preload_is_type_known (ce , & fptr -> common .arg_info [-1 ].type ) &&
3892
- preload_is_method_maybe_override (ce , lcname )) {
3929
+ preload_is_method_maybe_override (deps , ce , lcname )) {
3893
3930
return 0 ;
3894
3931
}
3895
3932
}
3896
3933
for (i = 0 ; i < fptr -> common .num_args ; i ++ ) {
3897
3934
if (!preload_is_type_known (ce , & fptr -> common .arg_info [i ].type ) &&
3898
- preload_is_method_maybe_override (ce , lcname )) {
3935
+ preload_is_method_maybe_override (deps , ce , lcname )) {
3899
3936
return 0 ;
3900
3937
}
3901
3938
}
@@ -3907,10 +3944,9 @@ static void preload_link(void)
3907
3944
{
3908
3945
zval * zv ;
3909
3946
zend_persistent_script * script ;
3910
- zend_class_entry * ce , * parent , * p ;
3947
+ zend_class_entry * ce ;
3911
3948
zend_string * key ;
3912
- bool found , changed ;
3913
- uint32_t i ;
3949
+ bool changed ;
3914
3950
3915
3951
/* Resolve class dependencies */
3916
3952
do {
@@ -3933,44 +3969,7 @@ static void preload_link(void)
3933
3969
zend_string_release (key );
3934
3970
}
3935
3971
3936
- parent = NULL ;
3937
-
3938
- if (ce -> parent_name ) {
3939
- key = zend_string_tolower (ce -> parent_name );
3940
- parent = zend_hash_find_ptr (EG (class_table ), key );
3941
- zend_string_release (key );
3942
- if (!parent ) continue ;
3943
- }
3944
-
3945
- if (ce -> num_interfaces ) {
3946
- found = 1 ;
3947
- for (i = 0 ; i < ce -> num_interfaces ; i ++ ) {
3948
- p = zend_hash_find_ptr (EG (class_table ), ce -> interface_names [i ].lc_name );
3949
- if (!p ) {
3950
- found = 0 ;
3951
- break ;
3952
- }
3953
- }
3954
- if (!found ) continue ;
3955
- }
3956
-
3957
- if (ce -> num_traits ) {
3958
- found = 1 ;
3959
- for (i = 0 ; i < ce -> num_traits ; i ++ ) {
3960
- p = zend_hash_find_ptr (EG (class_table ), ce -> trait_names [i ].lc_name );
3961
- if (!p ) {
3962
- found = 0 ;
3963
- break ;
3964
- }
3965
- }
3966
- if (!found ) continue ;
3967
- }
3968
-
3969
- /* TODO: This is much more restrictive than necessary. We only need to actually
3970
- * know the types for covariant checks, but don't need them if we can ensure
3971
- * compatibility through a simple string comparison. We could improve this using
3972
- * a more general version of zend_can_early_bind(). */
3973
- if (!preload_needed_types_known (ce )) {
3972
+ if (!preload_can_resolve_deps (ce )) {
3974
3973
continue ;
3975
3974
}
3976
3975
0 commit comments