|
|
|
@ -326,13 +326,16 @@ static zend_always_inline int zend_verify_property_access(zend_property_info *pr |
|
|
|
if (property_info->flags & ZEND_ACC_PUBLIC) { |
|
|
|
return 1; |
|
|
|
} else if (property_info->flags & ZEND_ACC_PRIVATE) { |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
if (property_info->ce == ce) { |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
} |
|
|
|
return ce == scope; |
|
|
|
} |
|
|
|
return (ce == scope || property_info->ce == scope); |
|
|
|
} else if (property_info->flags & ZEND_ACC_PROTECTED) { |
|
|
|
} else { |
|
|
|
ZEND_ASSERT(property_info->flags & ZEND_ACC_PROTECTED); |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
@ -377,39 +380,67 @@ static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *c |
|
|
|
if (EXPECTED(zv != NULL)) { |
|
|
|
property_info = (zend_property_info*)Z_PTR_P(zv); |
|
|
|
flags = property_info->flags; |
|
|
|
if (UNEXPECTED((flags & ZEND_ACC_SHADOW) != 0)) { |
|
|
|
/* if it's a shadow - go to access it's private */ |
|
|
|
property_info = NULL; |
|
|
|
} else { |
|
|
|
if (EXPECTED(zend_verify_property_access(property_info, ce) != 0)) { |
|
|
|
if (UNEXPECTED(!(flags & ZEND_ACC_CHANGED)) |
|
|
|
|| UNEXPECTED((flags & ZEND_ACC_PRIVATE))) { |
|
|
|
if (UNEXPECTED((flags & ZEND_ACC_STATIC) != 0)) { |
|
|
|
if (!silent) { |
|
|
|
zend_error(E_NOTICE, "Accessing static property %s::$%s as non static", ZSTR_VAL(ce->name), ZSTR_VAL(member)); |
|
|
|
} |
|
|
|
return ZEND_DYNAMIC_PROPERTY_OFFSET; |
|
|
|
|
|
|
|
if (flags & ZEND_ACC_PUBLIC) { |
|
|
|
check_changed: |
|
|
|
if (UNEXPECTED(!(flags & ZEND_ACC_CHANGED))) { |
|
|
|
no_changed: |
|
|
|
if (UNEXPECTED((flags & ZEND_ACC_STATIC) != 0)) { |
|
|
|
if (!silent) { |
|
|
|
zend_error(E_NOTICE, "Accessing static property %s::$%s as non static", ZSTR_VAL(ce->name), ZSTR_VAL(member)); |
|
|
|
} |
|
|
|
goto exit; |
|
|
|
return ZEND_DYNAMIC_PROPERTY_OFFSET; |
|
|
|
} |
|
|
|
goto exit; |
|
|
|
} |
|
|
|
goto check_scope; |
|
|
|
} else if (flags & ZEND_ACC_PRIVATE) { |
|
|
|
if (property_info->ce != ce) { |
|
|
|
/* if it's a shadow - go to access it's private */ |
|
|
|
property_info = NULL; |
|
|
|
goto check_scope; |
|
|
|
} else { |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
} |
|
|
|
if (ce == scope) { |
|
|
|
goto no_changed; |
|
|
|
} else { |
|
|
|
/* Try to look in the scope instead */ |
|
|
|
property_info = ZEND_WRONG_PROPERTY_INFO; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
ZEND_ASSERT(flags & ZEND_ACC_PROTECTED); |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
} |
|
|
|
if (zend_check_protected(property_info->ce, scope)) { |
|
|
|
goto check_changed; |
|
|
|
} else { |
|
|
|
/* Try to look in the scope instead */ |
|
|
|
property_info = ZEND_WRONG_PROPERTY_INFO; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
check_scope: |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (scope != ce |
|
|
|
&& scope |
|
|
|
&& is_derived_class(ce, scope) |
|
|
|
&& (zv = zend_hash_find(&scope->properties_info, member)) != NULL |
|
|
|
&& ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE) { |
|
|
|
&& ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE |
|
|
|
&& ((zend_property_info*)Z_PTR_P(zv))->ce == scope) { |
|
|
|
property_info = (zend_property_info*)Z_PTR_P(zv); |
|
|
|
if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) != 0)) { |
|
|
|
return ZEND_DYNAMIC_PROPERTY_OFFSET; |
|
|
|
@ -457,38 +488,66 @@ ZEND_API zend_property_info *zend_get_property_info(zend_class_entry *ce, zend_s |
|
|
|
if (EXPECTED(zv != NULL)) { |
|
|
|
property_info = (zend_property_info*)Z_PTR_P(zv); |
|
|
|
flags = property_info->flags; |
|
|
|
if (UNEXPECTED((flags & ZEND_ACC_SHADOW) != 0)) { |
|
|
|
/* if it's a shadow - go to access it's private */ |
|
|
|
property_info = NULL; |
|
|
|
} else { |
|
|
|
if (EXPECTED(zend_verify_property_access(property_info, ce) != 0)) { |
|
|
|
if (UNEXPECTED(!(flags & ZEND_ACC_CHANGED)) |
|
|
|
|| UNEXPECTED((flags & ZEND_ACC_PRIVATE))) { |
|
|
|
if (UNEXPECTED((flags & ZEND_ACC_STATIC) != 0)) { |
|
|
|
if (!silent) { |
|
|
|
zend_error(E_NOTICE, "Accessing static property %s::$%s as non static", ZSTR_VAL(ce->name), ZSTR_VAL(member)); |
|
|
|
} |
|
|
|
|
|
|
|
if (flags & ZEND_ACC_PUBLIC) { |
|
|
|
check_changed: |
|
|
|
if (UNEXPECTED(!(flags & ZEND_ACC_CHANGED))) { |
|
|
|
no_changed: |
|
|
|
if (UNEXPECTED((flags & ZEND_ACC_STATIC) != 0)) { |
|
|
|
if (!silent) { |
|
|
|
zend_error(E_NOTICE, "Accessing static property %s::$%s as non static", ZSTR_VAL(ce->name), ZSTR_VAL(member)); |
|
|
|
} |
|
|
|
goto exit; |
|
|
|
} |
|
|
|
goto exit; |
|
|
|
} |
|
|
|
goto check_scope; |
|
|
|
} else if (flags & ZEND_ACC_PRIVATE) { |
|
|
|
if (property_info->ce != ce) { |
|
|
|
/* if it's a shadow - go to access it's private */ |
|
|
|
property_info = NULL; |
|
|
|
goto check_scope; |
|
|
|
} else { |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
} |
|
|
|
if (ce == scope) { |
|
|
|
goto no_changed; |
|
|
|
} else { |
|
|
|
/* Try to look in the scope instead */ |
|
|
|
property_info = ZEND_WRONG_PROPERTY_INFO; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
ZEND_ASSERT(flags & ZEND_ACC_PROTECTED); |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
} |
|
|
|
if (zend_check_protected(property_info->ce, scope)) { |
|
|
|
goto check_changed; |
|
|
|
} else { |
|
|
|
/* Try to look in the scope instead */ |
|
|
|
property_info = ZEND_WRONG_PROPERTY_INFO; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
check_scope: |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (scope != ce |
|
|
|
&& scope |
|
|
|
&& is_derived_class(ce, scope) |
|
|
|
&& (zv = zend_hash_find(&scope->properties_info, member)) != NULL |
|
|
|
&& ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE) { |
|
|
|
&& ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE |
|
|
|
&& ((zend_property_info*)Z_PTR_P(zv))->ce == scope) { |
|
|
|
property_info = (zend_property_info*)Z_PTR_P(zv); |
|
|
|
} else if (UNEXPECTED(property_info == NULL)) { |
|
|
|
exit_dynamic: |
|
|
|
@ -519,35 +578,57 @@ ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_inf |
|
|
|
const char *prop_name; |
|
|
|
zend_string *member; |
|
|
|
size_t prop_name_len; |
|
|
|
zend_class_entry *scope; |
|
|
|
|
|
|
|
if (ZSTR_VAL(prop_info_name)[0] == 0) { |
|
|
|
zend_unmangle_property_name_ex(prop_info_name, &class_name, &prop_name, &prop_name_len); |
|
|
|
member = zend_string_init(prop_name, prop_name_len, 0); |
|
|
|
} else { |
|
|
|
member = zend_string_copy(prop_info_name); |
|
|
|
} |
|
|
|
property_info = zend_get_property_info(zobj->ce, member, 1); |
|
|
|
zend_string_release_ex(member, 0); |
|
|
|
if (property_info == NULL) { |
|
|
|
/* undefined public property */ |
|
|
|
if (class_name && class_name[0] != '*') { |
|
|
|
/* we we're looking for a private prop */ |
|
|
|
property_info = zend_get_property_info(zobj->ce, member, 1); |
|
|
|
zend_string_release_ex(member, 0); |
|
|
|
if (property_info == NULL) { |
|
|
|
if (class_name[0] != '*') { |
|
|
|
/* we we're looking for a private prop */ |
|
|
|
return FAILURE; |
|
|
|
} |
|
|
|
return SUCCESS; |
|
|
|
} else if (property_info == ZEND_WRONG_PROPERTY_INFO) { |
|
|
|
return FAILURE; |
|
|
|
} |
|
|
|
return SUCCESS; |
|
|
|
} else if (property_info == ZEND_WRONG_PROPERTY_INFO) { |
|
|
|
return FAILURE; |
|
|
|
} |
|
|
|
if (class_name && class_name[0] != '*') { |
|
|
|
if (!(property_info->flags & ZEND_ACC_PRIVATE)) { |
|
|
|
/* we we're looking for a private prop but found a non private one of the same name */ |
|
|
|
return FAILURE; |
|
|
|
} else if (strcmp(ZSTR_VAL(prop_info_name)+1, ZSTR_VAL(property_info->name)+1)) { |
|
|
|
/* we we're looking for a private prop but found a private one of the same name but another class */ |
|
|
|
if (class_name[0] != '*') { |
|
|
|
if (!(property_info->flags & ZEND_ACC_PRIVATE)) { |
|
|
|
/* we we're looking for a private prop but found a non private one of the same name */ |
|
|
|
return FAILURE; |
|
|
|
} else if (strcmp(ZSTR_VAL(prop_info_name)+1, ZSTR_VAL(property_info->name)+1)) { |
|
|
|
/* we we're looking for a private prop but found a private one of the same name but another class */ |
|
|
|
return FAILURE; |
|
|
|
} |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
} |
|
|
|
if (property_info->ce == scope) { |
|
|
|
return SUCCESS; |
|
|
|
} else { |
|
|
|
return FAILURE; |
|
|
|
} |
|
|
|
} else { |
|
|
|
ZEND_ASSERT(property_info->flags & ZEND_ACC_PROTECTED); |
|
|
|
if (EG(fake_scope)) { |
|
|
|
scope = EG(fake_scope); |
|
|
|
} else { |
|
|
|
scope = zend_get_executed_scope(); |
|
|
|
} |
|
|
|
return zend_check_protected(property_info->ce, scope) ? SUCCESS : FAILURE; |
|
|
|
} |
|
|
|
} else { |
|
|
|
property_info = zend_get_property_info(zobj->ce, prop_info_name, 1); |
|
|
|
if (property_info == NULL || property_info == ZEND_WRONG_PROPERTY_INFO) { |
|
|
|
return FAILURE; |
|
|
|
} |
|
|
|
ZEND_ASSERT(property_info->flags & ZEND_ACC_PUBLIC); |
|
|
|
return SUCCESS; |
|
|
|
} |
|
|
|
return zend_verify_property_access(property_info, zobj->ce) ? SUCCESS : FAILURE; |
|
|
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|
@ -1474,7 +1555,8 @@ ZEND_API zend_function *zend_std_get_constructor(zend_object *zobj) /* {{{ */ |
|
|
|
constructor = NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
} else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) { |
|
|
|
} else { |
|
|
|
ZEND_ASSERT(constructor->common.fn_flags & ZEND_ACC_PROTECTED); |
|
|
|
/* Ensure that if we're calling a protected function, we're allowed to do so. |
|
|
|
* Constructors only have prototype if they are defined by an interface but |
|
|
|
* it is the compilers responsibility to take care of the prototype. |
|
|
|
|