summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/bug29689.phpt31
-rw-r--r--Zend/zend_compile.c16
-rw-r--r--Zend/zend_compile.h3
-rw-r--r--Zend/zend_object_handlers.c35
-rw-r--r--Zend/zend_reflection_api.c21
-rw-r--r--ext/reflection/php_reflection.c21
6 files changed, 84 insertions, 43 deletions
diff --git a/Zend/tests/bug29689.phpt b/Zend/tests/bug29689.phpt
index 003499f378..e0a037a1b6 100644
--- a/Zend/tests/bug29689.phpt
+++ b/Zend/tests/bug29689.phpt
@@ -4,10 +4,11 @@ Bug #29689 (default value of protected member overrides default value of private
<?php
class foo {
private $foo = 'foo';
+ private $foo2 = 'foo2';
function printFoo()
{
- echo __CLASS__, ': ', $this->foo, "\n";
+ echo __CLASS__, ': ', $this->foo, " ", $this->foo2, "\n";
}
}
@@ -17,41 +18,45 @@ class bar extends foo {
function printFoo()
{
parent::printFoo();
- echo __CLASS__, ': ', $this->foo, "\n";
+ echo __CLASS__, ': ', $this->foo, " ", $this->foo2, "\n";
}
}
class baz extends bar {
protected $foo = 'baz';
+ protected $foo2 = 'baz2';
}
class bar2 extends foo {
function printFoo()
{
parent::printFoo();
- echo __CLASS__, ': ', $this->foo, "\n";
+ echo __CLASS__, ': ', $this->foo, " ", $this->foo2, "\n";
}
}
class baz2 extends bar2 {
protected $foo = 'baz2';
+ protected $foo2 = 'baz22';
}
$bar = new bar;
$bar->printFoo();
-echo "---\n";
+echo "---baz--\n";
$baz = new baz();
$baz->printFoo();
-echo "---\n";
+echo "---baz2--\n";
$baz = new baz2();
$baz->printFoo();
?>
---EXPECT--
-foo: foo
+--EXPECTF--
+foo: foo foo2
bar: bar
----
-foo: foo
-bar: baz
----
-foo: foo
-bar2: baz2
+Notice: Undefined property: bar::$foo2 in %s on line %d
+
+---baz--
+foo: foo foo2
+bar: baz baz2
+---baz2--
+foo: foo foo2
+bar2: baz2 baz22
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 7e95d0fcdb..67043fa448 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -1982,9 +1982,18 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro
zend_property_info *child_info;
zend_class_entry *parent_ce = ce->parent;
- if (parent_info->flags & ZEND_ACC_PRIVATE) {
+ if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) {
if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) {
child_info->flags |= ZEND_ACC_CHANGED;
+ } else {
+ zend_hash_quick_update(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, parent_info, sizeof(zend_property_info), (void **) &child_info);
+ if(ce->type & ZEND_INTERNAL_CLASS) {
+ zend_duplicate_property_info_internal(child_info);
+ } else {
+ zend_duplicate_property_info(child_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 */
}
return 0; /* don't copy access information to child */
}
@@ -1996,6 +2005,11 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro
(child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->arKey);
}
+
+ if(parent_info->flags & ZEND_ACC_CHANGED) {
+ child_info->flags |= ZEND_ACC_CHANGED;
+ }
+
if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
zend_error(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name, hash_key->arKey, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
} else if (child_info->flags & ZEND_ACC_IMPLICIT_PUBLIC) {
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 205da32811..f6a3a8bc38 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -133,6 +133,9 @@ typedef struct _zend_try_catch_element {
/* method flag (bc only), any method that has this flag can be used statically and non statically. */
#define ZEND_ACC_ALLOW_STATIC 0x10000
+/* shadow of parent's private method/property */
+#define ZEND_ACC_SHADOW 0x20000
+
char *zend_visibility_string(zend_uint fn_flags);
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index a0348a1ac4..dd86080e6d 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -160,22 +160,27 @@ ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce
}
h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
if (zend_hash_quick_find(&ce->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &property_info)==SUCCESS) {
- if (zend_verify_property_access(property_info, ce TSRMLS_CC)) {
- if (property_info->flags & ZEND_ACC_CHANGED
- && !(property_info->flags & ZEND_ACC_PRIVATE)) {
- /* We still need to make sure that we're not in a context
- * where the right property is a different 'statically linked' private
- * continue checking below...
- */
- } else {
- if (!silent && (property_info->flags & ZEND_ACC_STATIC)) {
- zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name, Z_STRVAL_P(member));
+ if(property_info->flags & ZEND_ACC_SHADOW) {
+ /* if it's a shadow - go to access it's private */
+ property_info = NULL;
+ } else {
+ if (zend_verify_property_access(property_info, ce TSRMLS_CC)) {
+ if (property_info->flags & ZEND_ACC_CHANGED
+ && !(property_info->flags & ZEND_ACC_PRIVATE)) {
+ /* We still need to make sure that we're not in a context
+ * where the right property is a different 'statically linked' private
+ * continue checking below...
+ */
+ } else {
+ if (!silent && (property_info->flags & ZEND_ACC_STATIC)) {
+ zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name, Z_STRVAL_P(member));
+ }
+ return property_info;
}
- return property_info;
+ } else {
+ /* Try to look in the scope instead */
+ denied_access = 1;
}
- } else {
- /* Try to look in the scope instead */
- denied_access = 1;
}
}
if (EG(scope) != ce
@@ -740,7 +745,7 @@ ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *propert
zend_property_info *property_info;
zend_property_info std_property_info;
- if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE) {
+ if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE || (property_info->flags & ZEND_ACC_SHADOW)) {
std_property_info.flags = ZEND_ACC_PUBLIC;
std_property_info.name = property_name;
std_property_info.name_length = property_name_len;
diff --git a/Zend/zend_reflection_api.c b/Zend/zend_reflection_api.c
index 133aa80fdd..ae7a6d3b75 100644
--- a/Zend/zend_reflection_api.c
+++ b/Zend/zend_reflection_api.c
@@ -257,7 +257,7 @@ static void _extension_string(string *str, zend_module_entry *module, char *inde
/* {{{ _class_string */
static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent TSRMLS_DC)
{
- int count, count_static_props = 0, count_static_funcs = 0;
+ int count, count_static_props = 0, count_static_funcs = 0, count_shadow_props = 0;
string sub_indent;
string_init(&sub_indent);
@@ -349,7 +349,9 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
- if (prop->flags & ZEND_ACC_STATIC) {
+ if(prop->flags & ZEND_ACC_SHADOW) {
+ count_shadow_props++;
+ } else if (prop->flags & ZEND_ACC_STATIC) {
count_static_props++;
}
zend_hash_move_forward_ex(&ce->properties_info, &pos);
@@ -365,9 +367,10 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
- if (prop->flags & ZEND_ACC_STATIC) {
+ if ((prop->flags & ZEND_ACC_STATIC) && !(prop->flags & ZEND_ACC_SHADOW)) {
_property_string(str, prop, NULL, sub_indent.string TSRMLS_CC);
}
+
zend_hash_move_forward_ex(&ce->properties_info, &pos);
}
}
@@ -415,7 +418,7 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
/* Default/Implicit properties */
if (&ce->properties_info) {
- count = zend_hash_num_elements(&ce->properties_info) - count_static_props;
+ count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props;
string_printf(str, "\n%s - Properties [%d] {\n", indent, count);
if (count > 0) {
HashPosition pos;
@@ -424,7 +427,7 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
- if (!(prop->flags & ZEND_ACC_STATIC)) {
+ if (!(prop->flags & (ZEND_ACC_STATIC|ZEND_ACC_SHADOW))) {
_property_string(str, prop, NULL, sub_indent.string TSRMLS_CC);
}
zend_hash_move_forward_ex(&ce->properties_info, &pos);
@@ -2724,7 +2727,7 @@ ZEND_METHOD(reflection_class, getProperty)
}
GET_REFLECTION_OBJECT_PTR(ce);
- if (zend_hash_find(&ce->properties_info, name, name_len + 1, (void**) &property_info) == SUCCESS) {
+ if (zend_hash_find(&ce->properties_info, name, name_len + 1, (void**) &property_info) == SUCCESS && (property_info->flags & ZEND_ACC_SHADOW) == 0) {
reflection_property_factory(ce, property_info, return_value TSRMLS_CC);
} else {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
@@ -2742,6 +2745,10 @@ static int _addproperty(zend_property_info *pptr, int num_args, va_list args, ze
zval *retval = va_arg(args, zval*);
long filter = va_arg(args, long);
+ if (pptr->flags & ZEND_ACC_SHADOW) {
+ return 0;
+ }
+
if (pptr->flags & filter) {
TSRMLS_FETCH();
ALLOC_ZVAL(property);
@@ -3248,7 +3255,7 @@ ZEND_METHOD(reflection_property, __construct)
/* returns out of this function */
}
- if (zend_hash_find(&ce->properties_info, name_str, name_len + 1, (void **) &property_info) == FAILURE) {
+ if (zend_hash_find(&ce->properties_info, name_str, name_len + 1, (void **) &property_info) == FAILURE || (property_info->flags | ZEND_ACC_SHADOW)) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
"Property %s::$%s does not exist", ce->name, name_str);
return;
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 133aa80fdd..ae7a6d3b75 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -257,7 +257,7 @@ static void _extension_string(string *str, zend_module_entry *module, char *inde
/* {{{ _class_string */
static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent TSRMLS_DC)
{
- int count, count_static_props = 0, count_static_funcs = 0;
+ int count, count_static_props = 0, count_static_funcs = 0, count_shadow_props = 0;
string sub_indent;
string_init(&sub_indent);
@@ -349,7 +349,9 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
- if (prop->flags & ZEND_ACC_STATIC) {
+ if(prop->flags & ZEND_ACC_SHADOW) {
+ count_shadow_props++;
+ } else if (prop->flags & ZEND_ACC_STATIC) {
count_static_props++;
}
zend_hash_move_forward_ex(&ce->properties_info, &pos);
@@ -365,9 +367,10 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
- if (prop->flags & ZEND_ACC_STATIC) {
+ if ((prop->flags & ZEND_ACC_STATIC) && !(prop->flags & ZEND_ACC_SHADOW)) {
_property_string(str, prop, NULL, sub_indent.string TSRMLS_CC);
}
+
zend_hash_move_forward_ex(&ce->properties_info, &pos);
}
}
@@ -415,7 +418,7 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
/* Default/Implicit properties */
if (&ce->properties_info) {
- count = zend_hash_num_elements(&ce->properties_info) - count_static_props;
+ count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props;
string_printf(str, "\n%s - Properties [%d] {\n", indent, count);
if (count > 0) {
HashPosition pos;
@@ -424,7 +427,7 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
- if (!(prop->flags & ZEND_ACC_STATIC)) {
+ if (!(prop->flags & (ZEND_ACC_STATIC|ZEND_ACC_SHADOW))) {
_property_string(str, prop, NULL, sub_indent.string TSRMLS_CC);
}
zend_hash_move_forward_ex(&ce->properties_info, &pos);
@@ -2724,7 +2727,7 @@ ZEND_METHOD(reflection_class, getProperty)
}
GET_REFLECTION_OBJECT_PTR(ce);
- if (zend_hash_find(&ce->properties_info, name, name_len + 1, (void**) &property_info) == SUCCESS) {
+ if (zend_hash_find(&ce->properties_info, name, name_len + 1, (void**) &property_info) == SUCCESS && (property_info->flags & ZEND_ACC_SHADOW) == 0) {
reflection_property_factory(ce, property_info, return_value TSRMLS_CC);
} else {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
@@ -2742,6 +2745,10 @@ static int _addproperty(zend_property_info *pptr, int num_args, va_list args, ze
zval *retval = va_arg(args, zval*);
long filter = va_arg(args, long);
+ if (pptr->flags & ZEND_ACC_SHADOW) {
+ return 0;
+ }
+
if (pptr->flags & filter) {
TSRMLS_FETCH();
ALLOC_ZVAL(property);
@@ -3248,7 +3255,7 @@ ZEND_METHOD(reflection_property, __construct)
/* returns out of this function */
}
- if (zend_hash_find(&ce->properties_info, name_str, name_len + 1, (void **) &property_info) == FAILURE) {
+ if (zend_hash_find(&ce->properties_info, name_str, name_len + 1, (void **) &property_info) == FAILURE || (property_info->flags | ZEND_ACC_SHADOW)) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
"Property %s::$%s does not exist", ce->name, name_str);
return;