Created
April 22, 2024 18:35
-
-
Save dstogov/e58c5c1ae04ecce6dd963d708639f722 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c | |
index 491d68714b3..20c830db03f 100644 | |
--- a/Zend/zend_inheritance.c | |
+++ b/Zend/zend_inheritance.c | |
@@ -1081,13 +1081,13 @@ static void perform_delayable_implementation_check( | |
/** | |
* @param check_only Set to false to throw compile errors on incompatible methods, or true to return INHERITANCE_ERROR. | |
* @param checked Whether the compatibility check has already succeeded in zend_can_early_bind(). | |
- * @param force_mutable Whether we know that child may be modified, i.e. doesn't live in shm. | |
+ * @param child_zv the zval where the "child" may be cloned. It's NULL if we don't need cloning. | |
*/ | |
static zend_always_inline inheritance_status do_inheritance_check_on_method_ex( | |
zend_function *child, zend_class_entry *child_scope, | |
zend_function *parent, zend_class_entry *parent_scope, | |
zend_class_entry *ce, zval *child_zv, | |
- bool check_visibility, bool check_only, bool checked, bool force_mutable) /* {{{ */ | |
+ bool check_visibility, bool check_only, bool checked) /* {{{ */ | |
{ | |
uint32_t child_flags; | |
uint32_t parent_flags = parent->common.fn_flags; | |
@@ -1095,6 +1095,12 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex( | |
if (UNEXPECTED((parent_flags & ZEND_ACC_PRIVATE) && !(parent_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_CTOR))) { | |
if (!check_only) { | |
+ if (child_scope != ce && child->type == ZEND_USER_FUNCTION && child_zv) { | |
+ /* op_array wasn't duplicated yet */ | |
+ zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); | |
+ memcpy(new_function, child, sizeof(zend_op_array)); | |
+ Z_PTR_P(child_zv) = child = new_function; | |
+ } | |
child->common.fn_flags |= ZEND_ACC_CHANGED; | |
} | |
/* The parent method is private and not an abstract so we don't need to check any inheritance rules */ | |
@@ -1139,6 +1145,13 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex( | |
} | |
if (!check_only && (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) { | |
+ if (child_scope != ce && child->type == ZEND_USER_FUNCTION && child_zv) { | |
+ /* op_array wasn't duplicated yet */ | |
+ zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); | |
+ memcpy(new_function, child, sizeof(zend_op_array)); | |
+ Z_PTR_P(child_zv) = child = new_function; | |
+ child_zv = NULL; | |
+ } | |
child->common.fn_flags |= ZEND_ACC_CHANGED; | |
} | |
@@ -1154,17 +1167,18 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex( | |
parent = proto; | |
} | |
- if (!check_only && child->common.prototype != proto && child_zv) { | |
+ if (!check_only && child->common.prototype != proto) { | |
do { | |
- if (child->common.scope != ce && child->type == ZEND_USER_FUNCTION) { | |
+ if (child_scope != ce && child->type == ZEND_USER_FUNCTION) { | |
if (ce->ce_flags & ZEND_ACC_INTERFACE) { | |
/* Few parent interfaces contain the same method */ | |
break; | |
- } else { | |
+ } else if (child_zv) { | |
/* op_array wasn't duplicated yet */ | |
zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); | |
memcpy(new_function, child, sizeof(zend_op_array)); | |
Z_PTR_P(child_zv) = child = new_function; | |
+ child_zv = NULL; | |
} | |
} | |
child->common.prototype = proto; | |
@@ -1189,7 +1203,14 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex( | |
perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope); | |
} | |
- if (!check_only && (child->common.scope == ce || force_mutable)) { | |
+ if (!check_only && (child->common.fn_flags & ZEND_ACC_OVERRIDE)) { | |
+ if (child_scope != ce && child->type == ZEND_USER_FUNCTION && child_zv) { | |
+ /* op_array wasn't duplicated yet */ | |
+ zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); | |
+ memcpy(new_function, child, sizeof(zend_op_array)); | |
+ Z_PTR_P(child_zv) = child = new_function; | |
+ child_zv = NULL; | |
+ } | |
child->common.fn_flags &= ~ZEND_ACC_OVERRIDE; | |
} | |
@@ -1202,7 +1223,7 @@ static zend_never_inline void do_inheritance_check_on_method( | |
zend_function *parent, zend_class_entry *parent_scope, | |
zend_class_entry *ce, zval *child_zv, bool check_visibility) | |
{ | |
- do_inheritance_check_on_method_ex(child, child_scope, parent, parent_scope, ce, child_zv, check_visibility, 0, 0, /* force_mutable */ false); | |
+ do_inheritance_check_on_method_ex(child, child_scope, parent, parent_scope, ce, child_zv, check_visibility, 0, 0); | |
} | |
static zend_always_inline void do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce, bool is_interface, bool checked) /* {{{ */ | |
@@ -1220,7 +1241,7 @@ static zend_always_inline void do_inherit_method(zend_string *key, zend_function | |
if (checked) { | |
do_inheritance_check_on_method_ex( | |
func, func->common.scope, parent, parent->common.scope, ce, child, | |
- /* check_visibility */ 1, 0, checked, /* force_mutable */ false); | |
+ /* check_visibility */ 1, 0, checked); | |
} else { | |
do_inheritance_check_on_method( | |
func, func->common.scope, parent, parent->common.scope, ce, child, | |
@@ -1948,11 +1969,13 @@ static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_e | |
static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */ | |
{ | |
+ zval *existing_zv = zend_hash_find(&ce->function_table, key); | |
zend_function *existing_fn = NULL; | |
zend_function *new_fn; | |
bool check_inheritance = false; | |
- if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) { | |
+ if (existing_zv != NULL) { | |
+ existing_fn = Z_PTR_P(existing_zv); | |
/* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless | |
* of where it is coming from there is no conflict and we do not need to add it again */ | |
if (existing_fn->op_array.opcodes == fn->op_array.opcodes && | |
@@ -1970,7 +1993,7 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_ | |
*/ | |
do_inheritance_check_on_method( | |
existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce), | |
- ce, NULL, /* check_visibility */ 0); | |
+ ce, existing_zv, /* check_visibility */ 0); | |
return; | |
} | |
@@ -2011,7 +2034,7 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_ | |
* Check whether the trait method fulfills the inheritance requirements. */ | |
do_inheritance_check_on_method_ex( | |
fn, fixup_trait_scope(fn, ce), existing_fn, fixup_trait_scope(existing_fn, ce), | |
- ce, NULL, /* check_visibility */ 1, false, false, /* force_mutable */ true); | |
+ ce, NULL, /* check_visibility */ 1, false, false); | |
} | |
} | |
/* }}} */ | |
@@ -3267,7 +3290,7 @@ static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_e | |
do_inheritance_check_on_method_ex( | |
child_func, child_func->common.scope, | |
parent_func, parent_func->common.scope, | |
- ce, NULL, /* check_visibility */ 1, 1, 0, /* force_mutable */ false); | |
+ ce, NULL, /* check_visibility */ 1, 1, 0); | |
if (UNEXPECTED(status == INHERITANCE_WARNING)) { | |
overall_status = INHERITANCE_WARNING; | |
} else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment