|
31 | 31 | #include "zend_attributes.h" |
32 | 32 | #include "zend_constants.h" |
33 | 33 | #include "zend_observer.h" |
| 34 | +#include "zend_call_stack.h" |
34 | 35 |
|
35 | 36 | ZEND_API zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces) = NULL; |
36 | 37 | ZEND_API zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies) = NULL; |
@@ -2867,6 +2868,54 @@ static const zend_class_entry* find_first_property_definition(const zend_class_e |
2867 | 2868 | } |
2868 | 2869 | /* }}} */ |
2869 | 2870 |
|
| 2871 | +static bool zend_compare_constant_ast(zend_ast *lhs, zend_ast *rhs) { |
| 2872 | +#ifdef ZEND_CHECK_STACK_LIMIT |
| 2873 | + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { |
| 2874 | + zend_call_stack_size_error(); |
| 2875 | + return true; |
| 2876 | + } |
| 2877 | +#endif |
| 2878 | + |
| 2879 | + if (lhs->kind != rhs->kind) { |
| 2880 | + return false; |
| 2881 | + } |
| 2882 | + if (lhs->attr != rhs->attr) { |
| 2883 | + return false; |
| 2884 | + } |
| 2885 | + if (lhs->kind == ZEND_AST_ZVAL) { |
| 2886 | + if (!zend_is_identical(zend_ast_get_zval(lhs), zend_ast_get_zval(rhs))) { |
| 2887 | + return false; |
| 2888 | + } |
| 2889 | + } else if (lhs->kind == ZEND_AST_CONSTANT) { |
| 2890 | + if (!zend_string_equals(zend_ast_get_constant_name(lhs), zend_ast_get_constant_name(rhs))) { |
| 2891 | + return false; |
| 2892 | + } |
| 2893 | + } else if (zend_ast_is_list(lhs)) { |
| 2894 | + zend_ast_list *lhs_list = zend_ast_get_list(lhs); |
| 2895 | + zend_ast_list *rhs_list = zend_ast_get_list(rhs); |
| 2896 | + if (lhs_list->children != rhs_list->children) { |
| 2897 | + return false; |
| 2898 | + } |
| 2899 | + for (uint32_t i = 0; i < rhs_list->children; i++) { |
| 2900 | + zend_ast *lhs_child = lhs_list->child[i]; |
| 2901 | + zend_ast *rhs_child = rhs_list->child[i]; |
| 2902 | + if (!zend_compare_constant_ast(lhs_child, rhs_child)) { |
| 2903 | + return false; |
| 2904 | + } |
| 2905 | + } |
| 2906 | + } else { |
| 2907 | + for (uint32_t i = 0; i < zend_ast_get_num_children(lhs); i++) { |
| 2908 | + zend_ast *lhs_child = lhs->child[i]; |
| 2909 | + zend_ast *rhs_child = rhs->child[i]; |
| 2910 | + if (!zend_compare_constant_ast(lhs_child, rhs_child)) { |
| 2911 | + return false; |
| 2912 | + } |
| 2913 | + } |
| 2914 | + } |
| 2915 | + |
| 2916 | + return true; |
| 2917 | +} |
| 2918 | + |
2870 | 2919 | static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */ |
2871 | 2920 | { |
2872 | 2921 | zend_property_info *property_info; |
@@ -2922,6 +2971,43 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent |
2922 | 2971 | is_compatible = check_trait_property_or_constant_value_compatibility(ce, op1, op2); |
2923 | 2972 | } |
2924 | 2973 |
|
| 2974 | + if ((bool)property_info->attributes != (bool)colliding_prop->attributes) { |
| 2975 | +attributes_incompatible: |
| 2976 | + is_compatible = false; |
| 2977 | + } else if (property_info->attributes) { |
| 2978 | + if (zend_hash_num_elements(property_info->attributes) != zend_hash_num_elements(colliding_prop->attributes)) { |
| 2979 | + goto attributes_incompatible; |
| 2980 | + } |
| 2981 | + zval *colliding_attr_zv = colliding_prop->attributes->arPacked; |
| 2982 | + ZEND_HASH_PACKED_FOREACH_PTR(property_info->attributes, zend_attribute *attr) { |
| 2983 | + zend_attribute *colliding_attr = Z_PTR_P(colliding_attr_zv); |
| 2984 | + if (!zend_string_equals(attr->lcname, colliding_attr->lcname)) { |
| 2985 | + goto attributes_incompatible; |
| 2986 | + } |
| 2987 | + if (attr->argc != colliding_attr->argc) { |
| 2988 | + goto attributes_incompatible; |
| 2989 | + } |
| 2990 | + for (uint32_t i = 0; i < attr->argc; i++) { |
| 2991 | + zend_attribute_arg *attr_arg = &attr->args[i]; |
| 2992 | + zend_attribute_arg *colliding_attr_arg = &colliding_attr->args[i]; |
| 2993 | + if ((bool)attr_arg->name != (bool)colliding_attr_arg->name) { |
| 2994 | + goto attributes_incompatible; |
| 2995 | + } |
| 2996 | + if (attr_arg->name && !zend_string_equals(attr_arg->name, colliding_attr_arg->name)) { |
| 2997 | + goto attributes_incompatible; |
| 2998 | + } |
| 2999 | + if (Z_TYPE(attr_arg->value) == IS_CONSTANT_AST && Z_TYPE(colliding_attr_arg->value) == IS_CONSTANT_AST) { |
| 3000 | + if (!zend_compare_constant_ast(Z_ASTVAL(attr_arg->value), Z_ASTVAL(colliding_attr_arg->value))) { |
| 3001 | + goto attributes_incompatible; |
| 3002 | + } |
| 3003 | + } else if (!zend_is_identical(&attr_arg->value, &colliding_attr_arg->value)) { |
| 3004 | + goto attributes_incompatible; |
| 3005 | + } |
| 3006 | + } |
| 3007 | + colliding_attr_zv++; |
| 3008 | + } ZEND_HASH_FOREACH_END(); |
| 3009 | + } |
| 3010 | + |
2925 | 3011 | if (!is_compatible) { |
2926 | 3012 | zend_error_noreturn(E_COMPILE_ERROR, |
2927 | 3013 | "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed", |
|
0 commit comments