From 3a249e769b293afa454b18b8d894c3395683d26c Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 11 Sep 2018 11:56:45 +0300 Subject: [PATCH] Squashed commit of the following: commit 2d3cac9e005d6bef9aa73ab57cc674aa53125954 Author: Dmitry Stogov Date: Tue Sep 11 11:54:47 2018 +0300 Fixed static property access commit 31786ee27282f319f3ef2a07635b1f325cbd67c6 Author: Dmitry Stogov Date: Tue Sep 11 11:05:29 2018 +0300 Avoid duplicate checks commit 5ae502b979ea33d058d01a9421eec5afd0084e8d Author: Dmitry Stogov Date: Tue Sep 11 10:39:17 2018 +0300 Optimization commit 82c17f0e8af02c9cf7d1bbdae4e3158330148203 Author: Dmitry Stogov Date: Tue Sep 11 09:26:50 2018 +0300 Removed unused zend_duplicate_property_info() commit ba53d1d0dd91d5530328a11cac93ff9e75c462b5 Merge: eacc11b8fd c4b14370cf Author: Dmitry Stogov Date: Tue Sep 11 09:24:13 2018 +0300 Merge branch 'master' into shadow * master: 7.0.33 next Sync NEWS [ci skip] add NEWS for 76582 Enforce ordering of property compare in object comparisons Fixed wrong assertion Skip test on unsuitable env commit eacc11b8fdeb002ee6a149defd8b5a8c3412896a Author: Dmitry Stogov Date: Mon Sep 10 13:12:39 2018 +0300 Fixed failure of ext/spl/tests/array_017.phpt commit 62d1871430a1b81c84b790460afff0682648689a Author: Dmitry Stogov Date: Mon Sep 10 11:55:07 2018 +0300 Fixed issues commit 1d37e3a40e4d07c4b933ed6f9d2e649dd01180f0 Merge: d6c3f098b6 1e550e6f7e Author: Dmitry Stogov Date: Mon Sep 10 10:21:20 2018 +0300 Merge branch 'master' into shadow * master: Update NEWS Fix for bug #76582 Fix ssl stream reneg limit test to print only after first renegotiation Make a copy unconditionally Fix memory leak in pcre cache Remove not needed checking for Remove HAVE_ASSERT_H Add test for bug #76850 Fixed bug #76850 Exit code mangled by set locale/preg_match Remove empty PHP tags from test Fix #75273: php_zlib_inflate_filter() may not update bytes_consumed Fix PCRE2 exclusion and remove dead libs in Makefile.gcov Report mem leaks to stderr if no Win debugger is present Use combined assignment contanation operator Fixed bug #76796 Support fixed address mmap without replacement commit d6c3f098b6015e76d042691de0af2e1426c66829 Author: Dmitry Stogov Date: Fri Sep 7 13:56:30 2018 +0300 Get rid of ZEND_ACC_SHADOW --- UPGRADING.INTERNALS | 7 +- Zend/tests/bug70873.phpt | 2 +- Zend/zend_builtin_functions.c | 13 +- Zend/zend_compile.h | 5 +- Zend/zend_inheritance.c | 50 ++----- Zend/zend_object_handlers.c | 241 +++++++++++++++++++------------- Zend/zend_opcode.c | 2 +- ext/reflection/php_reflection.c | 31 ++-- ext/tidy/tests/027.phpt | 4 +- 9 files changed, 189 insertions(+), 166 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index f28e25aeca..b9126ed387 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -3,7 +3,7 @@ PHP 7.4 INTERNALS UPGRADE NOTES 1. Internal API changes a. php_sys_symlink() and php_sys_link() b. zend_lookup_class_ex() and zend_fetch_class_by_name() - c. Function flags + c. Function/property flags 2. Build system changes a. Unix build system changes @@ -23,12 +23,15 @@ PHP 7.4 INTERNALS UPGRADE NOTES changed to accept optional lower-case class name as zend_string*, instead of zval*. - c. Function flags changes + c. Function/property flags changes - ZEND_ACC_CTOR and ZEND_ACC_DTOR are removed. It's possible to check if method is a constructor/destructor using the following condition (func->commpon.scope->constructor == func). - ZEND_ACC_IMPLEMENTED_ABSTRACT is removed (it was used only internally during inheritance). + - ZEND_ACC_SHADOW property flag is removed. Instead of creating shadow + clone, now we use the same private property_info, and should also + check property_info->ce (in the same way as with methods). ======================== 2. Build system changes diff --git a/Zend/tests/bug70873.phpt b/Zend/tests/bug70873.phpt index 3edb7eac43..aecc0e879b 100644 --- a/Zend/tests/bug70873.phpt +++ b/Zend/tests/bug70873.phpt @@ -27,7 +27,7 @@ $b = new C; $b->bar(); ?> --EXPECTF-- -Fatal error: Uncaught Error: Cannot access property B::$x in %sbug70873.php:%d +Fatal error: Uncaught Error: Cannot access private property B::$x in %sbug70873.php:%d Stack trace: #0 %sbug70873.php(%d): B->bar() #1 {main} diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index d83169cac8..88c24ba8ae 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1097,13 +1097,10 @@ static void add_class_vars(zend_class_entry *scope, zend_class_entry *ce, int st zend_string *key; ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) { - if (((prop_info->flags & ZEND_ACC_SHADOW) && - prop_info->ce != scope) || - ((prop_info->flags & ZEND_ACC_PROTECTED) && + if (((prop_info->flags & ZEND_ACC_PROTECTED) && !zend_check_protected(prop_info->ce, scope)) || ((prop_info->flags & ZEND_ACC_PRIVATE) && - ce != scope && - prop_info->ce != scope)) { + prop_info->ce != scope)) { continue; } prop = NULL; @@ -1403,8 +1400,10 @@ ZEND_FUNCTION(property_exists) RETURN_NULL(); } - if ((property_info = zend_hash_find_ptr(&ce->properties_info, property)) != NULL - && (property_info->flags & ZEND_ACC_SHADOW) == 0) { + property_info = zend_hash_find_ptr(&ce->properties_info, property); + if (property_info != NULL + && (!(property_info->flags & ZEND_ACC_PRIVATE) + || property_info->ce == ce)) { RETURN_TRUE; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index b7f7014281..ba4550579e 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -212,15 +212,12 @@ typedef struct _zend_oparray_context { #define ZEND_ACC_PROTECTED (1 << 9) /* | X | X | X */ #define ZEND_ACC_PRIVATE (1 << 10) /* | X | X | X */ /* | | | */ -/* TODO: explain the name ??? | | | */ +/* Property or method overrides private one | | | */ #define ZEND_ACC_CHANGED (1 << 11) /* | X | X | */ /* | | | */ /* TODO: used only by ext/reflection ??? | | | */ #define ZEND_ACC_IMPLICIT_PUBLIC (1 << 12) /* | ? | ? | ? */ /* | | | */ -/* Shadow of parent's private method/property | | | */ -#define ZEND_ACC_SHADOW (1 << 17) /* | ? | X | */ -/* | | | */ /* Class Flags (unused: 0, 1, 3, 11-18, 21, 25...) | | | */ /* =========== | | | */ /* | | | */ diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index c6a89754c9..eef6c5b3a5 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -31,20 +31,6 @@ static void overridden_ptr_dtor(zval *zv) /* {{{ */ } /* }}} */ -static zend_property_info *zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */ -{ - zend_property_info* new_property_info; - - new_property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info)); - memcpy(new_property_info, property_info, sizeof(zend_property_info)); - zend_string_addref(new_property_info->name); - if (new_property_info->doc_comment) { - zend_string_addref(new_property_info->doc_comment); - } - return new_property_info; -} -/* }}} */ - static zend_property_info *zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */ { zend_property_info* new_property_info = pemalloc(sizeof(zend_property_info), 1); @@ -171,16 +157,14 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */ char *zend_visibility_string(uint32_t fn_flags) /* {{{ */ { - if (fn_flags & ZEND_ACC_PRIVATE) { - return "private"; - } - if (fn_flags & ZEND_ACC_PROTECTED) { - return "protected"; - } if (fn_flags & ZEND_ACC_PUBLIC) { return "public"; + } else if (fn_flags & ZEND_ACC_PRIVATE) { + return "private"; + } else { + ZEND_ASSERT(fn_flags & ZEND_ACC_PROTECTED); + return "protected"; } - return ""; } /* }}} */ @@ -684,7 +668,7 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke if (UNEXPECTED(child)) { child_info = Z_PTR_P(child); - if (UNEXPECTED(parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW))) { + if (UNEXPECTED(parent_info->flags & ZEND_ACC_PRIVATE)) { child_info->flags |= ZEND_ACC_CHANGED; } else { if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) { @@ -711,20 +695,10 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke } } } else { - if (UNEXPECTED(parent_info->flags & ZEND_ACC_PRIVATE)) { - if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) { - child_info = zend_duplicate_property_info_internal(parent_info); - } else { - child_info = zend_duplicate_property_info(parent_info); - } - child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */ - child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */ + if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) { + child_info = zend_duplicate_property_info_internal(parent_info); } else { - if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) { - child_info = zend_duplicate_property_info_internal(parent_info); - } else { - child_info = parent_info; - } + child_info = parent_info; } _zend_hash_append_ptr(&ce->properties_info, key, child_info); } @@ -1681,11 +1655,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent /* next: check for conflicts with current class */ if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) { - if (coliding_prop->flags & ZEND_ACC_SHADOW) { - zend_string_release_ex(coliding_prop->name, 0); - if (coliding_prop->doc_comment) { - zend_string_release_ex(coliding_prop->doc_comment, 0); - } + if ((coliding_prop->flags & ZEND_ACC_PRIVATE) && coliding_prop->ce != ce) { zend_hash_del(&ce->properties_info, prop_name); flags |= ZEND_ACC_CHANGED; } else { diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 29fd0b29bc..a7a863ff12 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -325,22 +325,19 @@ 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) { + } else { if (EG(fake_scope)) { scope = EG(fake_scope); } else { scope = zend_get_executed_scope(); } - return (ce == scope || property_info->ce == scope); - } else if (property_info->flags & ZEND_ACC_PROTECTED) { - if (EG(fake_scope)) { - scope = EG(fake_scope); + if (property_info->flags & ZEND_ACC_PRIVATE) { + return property_info->ce == scope; } else { - scope = zend_get_executed_scope(); + ZEND_ASSERT(property_info->flags & ZEND_ACC_PROTECTED); + return zend_check_protected(property_info->ce, scope); } - return zend_check_protected(property_info->ce, scope); } - return 0; } /* }}} */ @@ -377,39 +374,62 @@ 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) { + if (!(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 (EG(fake_scope)) { + scope = EG(fake_scope); + } else { + scope = zend_get_executed_scope(); + } + if (flags & ZEND_ACC_PRIVATE) { + if (property_info->ce == scope) { + goto no_changed; + } else if (property_info->ce != ce) { + /* if it's a shadow - go to access it's private */ + property_info = NULL; + } else { + /* Try to look in the scope instead */ + property_info = ZEND_WRONG_PROPERTY_INFO; } } else { - /* Try to look in the scope instead */ - property_info = ZEND_WRONG_PROPERTY_INFO; + ZEND_ASSERT(flags & ZEND_ACC_PROTECTED); + if (zend_check_protected(property_info->ce, scope)) { + if (!(flags & ZEND_ACC_CHANGED)) { + goto no_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 +477,61 @@ 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) { + if (!(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 (EG(fake_scope)) { + scope = EG(fake_scope); + } else { + scope = zend_get_executed_scope(); + } + if (flags & ZEND_ACC_PRIVATE) { + if (property_info->ce == scope) { + goto no_changed; + } else if (property_info->ce != ce) { + /* if it's a shadow - go to access it's private */ + property_info = NULL; + } else { + /* Try to look in the scope instead */ + property_info = ZEND_WRONG_PROPERTY_INFO; } } else { - /* Try to look in the scope instead */ - property_info = ZEND_WRONG_PROPERTY_INFO; + ZEND_ASSERT(flags & ZEND_ACC_PROTECTED); + if (zend_check_protected(property_info->ce, scope)) { + if (!(flags & ZEND_ACC_CHANGED)) { + goto no_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 +562,43 @@ 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; + } + } else { + ZEND_ASSERT(property_info->flags & ZEND_ACC_PROTECTED); + } + } else { + property_info = zend_get_property_info(zobj->ce, prop_info_name, 1); + if (property_info == NULL) { + return SUCCESS; + } else if (property_info == ZEND_WRONG_PROPERTY_INFO) { return FAILURE; } + ZEND_ASSERT(property_info->flags & ZEND_ACC_PUBLIC); } - return zend_verify_property_access(property_info, zobj->ce) ? SUCCESS : FAILURE; + return SUCCESS; } /* }}} */ @@ -1457,40 +1508,38 @@ ZEND_API zend_function *zend_std_get_constructor(zend_object *zobj) /* {{{ */ if (constructor) { if (constructor->op_array.fn_flags & ZEND_ACC_PUBLIC) { /* No further checks necessary */ - } else if (constructor->op_array.fn_flags & ZEND_ACC_PRIVATE) { - /* Ensure that if we're calling a private function, we're allowed to do so. - */ + } else { if (EG(fake_scope)) { scope = EG(fake_scope); } else { scope = zend_get_executed_scope(); } - if (UNEXPECTED(constructor->common.scope != scope)) { - if (scope) { - zend_throw_error(NULL, "Call to private %s::%s() from context '%s'", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name)); - constructor = NULL; - } else { - zend_throw_error(NULL, "Call to private %s::%s() from invalid context", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name)); - constructor = NULL; + if (constructor->op_array.fn_flags & ZEND_ACC_PRIVATE) { + /* Ensure that if we're calling a private function, we're allowed to do so. + */ + if (UNEXPECTED(constructor->common.scope != scope)) { + if (scope) { + zend_throw_error(NULL, "Call to private %s::%s() from context '%s'", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name)); + constructor = NULL; + } else { + zend_throw_error(NULL, "Call to private %s::%s() from invalid context", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name)); + constructor = NULL; + } } - } - } else if ((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. - */ - if (EG(fake_scope)) { - scope = EG(fake_scope); } else { - scope = zend_get_executed_scope(); - } - if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(constructor), scope))) { - if (scope) { - zend_throw_error(NULL, "Call to protected %s::%s() from context '%s'", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name)); - constructor = NULL; - } else { - zend_throw_error(NULL, "Call to protected %s::%s() from invalid context", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name)); - constructor = NULL; + 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. + */ + if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(constructor), scope))) { + if (scope) { + zend_throw_error(NULL, "Call to protected %s::%s() from context '%s'", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name)); + constructor = NULL; + } else { + zend_throw_error(NULL, "Call to protected %s::%s() from invalid context", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name)); + constructor = NULL; + } } } } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 46f9508b95..3019174ff2 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -242,7 +242,7 @@ ZEND_API void destroy_zend_class(zval *zv) efree(ce->default_static_members_table); } ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) { - if (prop_info->ce == ce || (prop_info->flags & ZEND_ACC_SHADOW)) { + if (prop_info->ce == ce) { zend_string_release_ex(prop_info->name, 0); if (prop_info->doc_comment) { zend_string_release_ex(prop_info->doc_comment, 0); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index eeb3ac66b8..fbacb9e92e 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -366,7 +366,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char zend_property_info *prop; ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { - if(prop->flags & ZEND_ACC_SHADOW) { + if ((prop->flags & ZEND_ACC_PRIVATE) && prop->ce != ce) { count_shadow_props++; } else if (prop->flags & ZEND_ACC_STATIC) { count_static_props++; @@ -380,7 +380,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char zend_property_info *prop; ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { - if ((prop->flags & ZEND_ACC_STATIC) && !(prop->flags & ZEND_ACC_SHADOW)) { + if ((prop->flags & ZEND_ACC_STATIC) && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)) { _property_string(str, prop, NULL, ZSTR_VAL(sub_indent)); } } ZEND_HASH_FOREACH_END(); @@ -427,7 +427,8 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char zend_property_info *prop; ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { - if (!(prop->flags & (ZEND_ACC_STATIC|ZEND_ACC_SHADOW))) { + if (!(prop->flags & ZEND_ACC_STATIC) + && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)) { _property_string(str, prop, NULL, ZSTR_VAL(sub_indent)); } } ZEND_HASH_FOREACH_END(); @@ -1242,7 +1243,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_string *name, tmp_ce = tmp_ce->parent; } - if (tmp_info && !(tmp_info->flags & ZEND_ACC_SHADOW)) { /* found something and it's not a parent's private */ + if (tmp_info && (!(tmp_info->flags & ZEND_ACC_PRIVATE) || tmp_info->ce == tmp_ce)) { /* found something and it's not a parent's private */ prop = tmp_info; } else { /* not found, use initial value */ ce = store_ce; @@ -3764,9 +3765,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value zend_string *key; ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) { - if (((prop_info->flags & ZEND_ACC_SHADOW) && - prop_info->ce != ce) || - ((prop_info->flags & ZEND_ACC_PROTECTED) && + if (((prop_info->flags & ZEND_ACC_PROTECTED) && !zend_check_protected(prop_info->ce, ce)) || ((prop_info->flags & ZEND_ACC_PRIVATE) && prop_info->ce != ce)) { @@ -4220,7 +4219,7 @@ ZEND_METHOD(reflection_class, hasProperty) GET_REFLECTION_OBJECT_PTR(ce); if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) { - if (property_info->flags & ZEND_ACC_SHADOW) { + if ((property_info->flags & ZEND_ACC_PRIVATE) && property_info->ce != ce) { RETURN_FALSE; } RETURN_TRUE; @@ -4255,7 +4254,7 @@ ZEND_METHOD(reflection_class, getProperty) GET_REFLECTION_OBJECT_PTR(ce); if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) { - if ((property_info->flags & ZEND_ACC_SHADOW) == 0) { + if (!(property_info->flags & ZEND_ACC_PRIVATE) || property_info->ce == ce) { reflection_property_factory(ce, name, property_info, return_value); return; } @@ -4297,7 +4296,10 @@ ZEND_METHOD(reflection_class, getProperty) } ce = ce2; - if ((property_info = zend_hash_str_find_ptr(&ce->properties_info, str_name, str_name_len)) != NULL && (property_info->flags & ZEND_ACC_SHADOW) == 0) { + property_info = zend_hash_str_find_ptr(&ce->properties_info, str_name, str_name_len); + if (property_info != NULL + && (!(property_info->flags & ZEND_ACC_PRIVATE) + || property_info->ce == ce)) { reflection_property_factory_str(ce, str_name, str_name_len, property_info, return_value); return; } @@ -4316,7 +4318,7 @@ static int _addproperty(zval *el, int num_args, va_list args, zend_hash_key *has zval *retval = va_arg(args, zval*); long filter = va_arg(args, long); - if (pptr->flags & ZEND_ACC_SHADOW) { + if ((pptr->flags & ZEND_ACC_PRIVATE) && pptr->ce != ce) { return 0; } @@ -5278,7 +5280,10 @@ ZEND_METHOD(reflection_property, __construct) /* returns out of this function */ } - if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) == NULL || (property_info->flags & ZEND_ACC_SHADOW)) { + property_info = zend_hash_find_ptr(&ce->properties_info, name); + if (property_info == NULL + || ((property_info->flags & ZEND_ACC_PRIVATE) + && property_info->ce != ce)) { /* Check for dynamic properties */ if (property_info == NULL && Z_TYPE_P(classname) == IS_OBJECT && Z_OBJ_HT_P(classname)->get_properties) { if (zend_hash_exists(Z_OBJ_HT_P(classname)->get_properties(classname), name)) { @@ -5530,7 +5535,7 @@ ZEND_METHOD(reflection_property, getDeclaringClass) ce = tmp_ce = ref->ce; while (tmp_ce && (tmp_info = zend_hash_find_ptr(&tmp_ce->properties_info, ref->unmangled_name)) != NULL) { - if (tmp_info->flags & ZEND_ACC_PRIVATE || tmp_info->flags & ZEND_ACC_SHADOW) { + if (tmp_info->flags & ZEND_ACC_PRIVATE) { /* it's a private property, so it can't be inherited */ break; } diff --git a/ext/tidy/tests/027.phpt b/ext/tidy/tests/027.phpt index cd984dd9e7..fb26a70f86 100644 --- a/ext/tidy/tests/027.phpt +++ b/ext/tidy/tests/027.phpt @@ -11,7 +11,7 @@ abstract class BaseClass { private static $tidyconfig; public function __construct() { - $this->tidyconfig = array( + self::$tidyconfig = array( 'indent' => false, 'clean' => true, 'merge-divs' => false, @@ -29,7 +29,7 @@ abstract class BaseClass { $data = "awerawer"; // in my code, $data is downloaded from a site $tidy = new tidy; - $tidy->parseString($data, $this->tidyconfig, 'utf8'); + $tidy->parseString($data, self::$tidyconfig, 'utf8'); $tidy->cleanRepair(); return $tidy; -- 2.40.0