From e9c3f9fcde1013cc1c9bdead7e16478a108d7907 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 13 May 2016 11:55:09 +0300 Subject: [PATCH] Fixed bug #72177 (Scope issue in __destruct after ReflectionProperty::setValue()) --- Zend/tests/bug72177.phpt | 35 +++++++++++++++++++++++++++++++++++ Zend/tests/bug72177_2.phpt | 34 ++++++++++++++++++++++++++++++++++ Zend/zend_object_handlers.c | 20 ++++++++++++++++++++ Zend/zend_objects.c | 7 +++++++ 4 files changed, 96 insertions(+) create mode 100644 Zend/tests/bug72177.phpt create mode 100644 Zend/tests/bug72177_2.phpt diff --git a/Zend/tests/bug72177.phpt b/Zend/tests/bug72177.phpt new file mode 100644 index 0000000000..b5658d354a --- /dev/null +++ b/Zend/tests/bug72177.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #72177 Scope issue in __destruct after ReflectionProperty::setValue() +--FILE-- +bar = null; + } +} + +class Parnt +{ + protected $child; + + public function doSomething() + { + $this->child = new Child(); + + $prop = new \ReflectionProperty($this, 'child'); + $prop->setAccessible(true); + $prop->setValue($this, null); + } +} + +$p = new Parnt(); +$p->doSomething(); + +echo "OK\n"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/bug72177_2.phpt b/Zend/tests/bug72177_2.phpt new file mode 100644 index 0000000000..718d6c061e --- /dev/null +++ b/Zend/tests/bug72177_2.phpt @@ -0,0 +1,34 @@ +--TEST-- +Bug #72177 Scope issue in __destruct after ReflectionProperty::setValue() +--FILE-- +bar); + } +} + +class Bar extends Foo +{ + private $baz = 'baz'; + private static $tab = 'tab'; + + public function __get(string $name) + { + var_dump($this->baz); + var_dump(self::$tab); + return $name; + } +} + +$r = new ReflectionProperty(Foo::class, 'bar'); + +$r->setAccessible(true); +echo "OK\n"; +?> +--EXPECT-- +OK diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 47fc542dbc..6aa5d731c5 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -191,6 +191,9 @@ ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp) /* {{{ * static void zend_std_call_getter(zval *object, zval *member, zval *retval) /* {{{ */ { zend_class_entry *ce = Z_OBJCE_P(object); + zend_class_entry *orig_fake_scope = EG(fake_scope); + + EG(fake_scope) = NULL; /* __get handler is called with one argument: property name @@ -202,6 +205,8 @@ static void zend_std_call_getter(zval *object, zval *member, zval *retval) /* {{ zend_call_method_with_1_params(object, ce, &ce->__get, ZEND_GET_FUNC_NAME, retval, member); zval_ptr_dtor(member); + + EG(fake_scope) = orig_fake_scope; } /* }}} */ @@ -210,6 +215,9 @@ static int zend_std_call_setter(zval *object, zval *member, zval *value) /* {{{ zval retval; int result; zend_class_entry *ce = Z_OBJCE_P(object); + zend_class_entry *orig_fake_scope = EG(fake_scope); + + EG(fake_scope) = NULL; if (Z_REFCOUNTED_P(member)) Z_ADDREF_P(member); if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); @@ -228,8 +236,10 @@ static int zend_std_call_setter(zval *object, zval *member, zval *value) /* {{{ if (Z_TYPE(retval) != IS_UNDEF) { result = i_zend_is_true(&retval) ? SUCCESS : FAILURE; zval_ptr_dtor(&retval); + EG(fake_scope) = orig_fake_scope; return result; } else { + EG(fake_scope) = orig_fake_scope; return FAILURE; } } @@ -238,6 +248,9 @@ static int zend_std_call_setter(zval *object, zval *member, zval *value) /* {{{ static void zend_std_call_unsetter(zval *object, zval *member) /* {{{ */ { zend_class_entry *ce = Z_OBJCE_P(object); + zend_class_entry *orig_fake_scope = EG(fake_scope); + + EG(fake_scope) = NULL; /* __unset handler is called with one argument: property name @@ -248,12 +261,17 @@ static void zend_std_call_unsetter(zval *object, zval *member) /* {{{ */ zend_call_method_with_1_params(object, ce, &ce->__unset, ZEND_UNSET_FUNC_NAME, NULL, member); zval_ptr_dtor(member); + + EG(fake_scope) = orig_fake_scope; } /* }}} */ static void zend_std_call_issetter(zval *object, zval *member, zval *retval) /* {{{ */ { zend_class_entry *ce = Z_OBJCE_P(object); + zend_class_entry *orig_fake_scope = EG(fake_scope); + + EG(fake_scope) = NULL; /* __isset handler is called with one argument: property name @@ -266,6 +284,8 @@ static void zend_std_call_issetter(zval *object, zval *member, zval *retval) /* zend_call_method_with_1_params(object, ce, &ce->__isset, ZEND_ISSET_FUNC_NAME, retval, member); zval_ptr_dtor(member); + + EG(fake_scope) = orig_fake_scope; } /* }}} */ diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 53d215d27e..b5f19b3045 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -91,7 +91,9 @@ ZEND_API void zend_objects_destroy_object(zend_object *object) if (destructor) { zend_object *old_exception; zval obj; + zend_class_entry *orig_fake_scope = NULL; + EG(fake_scope) = NULL; if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) { if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) { /* Ensure that if we're calling a private function, we're allowed to do so. @@ -104,12 +106,14 @@ ZEND_API void zend_objects_destroy_object(zend_object *object) "Call to private %s::__destruct() from context '%s'", ZSTR_VAL(object->ce->name), scope ? ZSTR_VAL(scope->name) : ""); + EG(fake_scope) = orig_fake_scope; return; } } else { zend_error(E_WARNING, "Call to private %s::__destruct() from context '' during shutdown ignored", ZSTR_VAL(object->ce->name)); + EG(fake_scope) = orig_fake_scope; return; } } else { @@ -123,12 +127,14 @@ ZEND_API void zend_objects_destroy_object(zend_object *object) "Call to protected %s::__destruct() from context '%s'", ZSTR_VAL(object->ce->name), scope ? ZSTR_VAL(scope->name) : ""); + EG(fake_scope) = orig_fake_scope; return; } } else { zend_error(E_WARNING, "Call to protected %s::__destruct() from context '' during shutdown ignored", ZSTR_VAL(object->ce->name)); + EG(fake_scope) = orig_fake_scope; return; } } @@ -159,6 +165,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object) } } zval_ptr_dtor(&obj); + EG(fake_scope) = orig_fake_scope; } } -- 2.40.0