]> granicus.if.org Git - php/commitdiff
Fixed bug #72177 (Scope issue in __destruct after ReflectionProperty::setValue())
authorDmitry Stogov <dmitry@zend.com>
Fri, 13 May 2016 08:55:09 +0000 (11:55 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 13 May 2016 08:55:09 +0000 (11:55 +0300)
Zend/tests/bug72177.phpt [new file with mode: 0644]
Zend/tests/bug72177_2.phpt [new file with mode: 0644]
Zend/zend_object_handlers.c
Zend/zend_objects.c

diff --git a/Zend/tests/bug72177.phpt b/Zend/tests/bug72177.phpt
new file mode 100644 (file)
index 0000000..b5658d3
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+Bug #72177 Scope issue in __destruct after ReflectionProperty::setValue()
+--FILE--
+<?php
+class Child
+{
+    protected $bar;
+
+    public function __destruct()
+    {
+        $this->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 (file)
index 0000000..718d6c0
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+Bug #72177 Scope issue in __destruct after ReflectionProperty::setValue()
+--FILE--
+<?php
+class Foo
+{
+    private $bar = 'bar';
+
+    public function __construct()
+    {
+        unset($this->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
index 47fc542dbc23f8798cf27eaa753a194562cc38f6..6aa5d731c5b6f2257a0b991e28b142291b6581c3 100644 (file)
@@ -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;
 }
 /* }}} */
 
index 53d215d27e7c4bd0ff43c1cc5cb573bdead37797..b5f19b3045439470ccfd47a83784853a0f5cde8c 100644 (file)
@@ -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;
        }
 }