Fixed bug #72177 (Scope issue in __destruct after ReflectionProperty::setValue())

This commit is contained in:
Dmitry Stogov 2016-05-13 11:55:09 +03:00
parent ee8f402af8
commit e9c3f9fcde
4 changed files with 96 additions and 0 deletions

35
Zend/tests/bug72177.phpt Normal file
View file

@ -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

View file

@ -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

View 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;
}
/* }}} */

View 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;
}
}