Skip to content

Commit be320e1

Browse files
committed
Real instance of lazy proxy may have less magic methods
1 parent b156471 commit be320e1

File tree

5 files changed

+113
-7
lines changed

5 files changed

+113
-7
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - isset
3+
--FILE--
4+
<?php
5+
6+
class RealInstance {
7+
public $_;
8+
}
9+
class Proxy extends RealInstance {
10+
public function __isset($name) {
11+
return isset($this->$name['']);
12+
}
13+
}
14+
$rc = new ReflectionClass(Proxy::class);
15+
$obj = $rc->newLazyProxy(function () {
16+
return new RealInstance;
17+
});
18+
var_dump(isset($obj->name['']));
19+
20+
?>
21+
--EXPECT--
22+
bool(false)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - get
3+
--FILE--
4+
<?php
5+
6+
class RealInstance {
7+
public $_;
8+
}
9+
class Proxy extends RealInstance {
10+
public function __get($name) {
11+
return $this->$name;
12+
}
13+
}
14+
$rc = new ReflectionClass(Proxy::class);
15+
$obj = $rc->newLazyProxy(function () {
16+
return new RealInstance;
17+
});
18+
var_dump($obj->name);
19+
20+
?>
21+
--EXPECTF--
22+
Warning: Undefined property: RealInstance::$name in %s on line %d
23+
NULL
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - set
3+
--FILE--
4+
<?php
5+
6+
#[AllowDynamicProperties]
7+
class RealInstance {
8+
public $_;
9+
}
10+
class Proxy extends RealInstance {
11+
public function __set($name, $value) {
12+
$this->$name = $value;
13+
}
14+
}
15+
$rc = new ReflectionClass(Proxy::class);
16+
$obj = $rc->newLazyProxy(function () {
17+
return new RealInstance;
18+
});
19+
$obj->name = 0;
20+
21+
var_dump($obj);
22+
23+
?>
24+
--EXPECTF--
25+
lazy proxy object(Proxy)#%d (1) {
26+
["instance"]=>
27+
object(RealInstance)#%d (2) {
28+
["_"]=>
29+
NULL
30+
["name"]=>
31+
int(0)
32+
}
33+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - proxy defines __isset(), both have guards
3+
--FILE--
4+
<?php
5+
6+
class RealInstance {
7+
public $_;
8+
public function __get($name) {
9+
printf("%s::%s\n", static::class, __FUNCTION__);
10+
}
11+
}
12+
class Proxy extends RealInstance {
13+
public function __isset($name) {
14+
printf("%s::%s\n", static::class, __FUNCTION__);
15+
return isset($this->$name['']);
16+
}
17+
}
18+
$rc = new ReflectionClass(Proxy::class);
19+
$obj = $rc->newLazyProxy(function () {
20+
return new RealInstance;
21+
});
22+
var_dump(isset($obj->name['']));
23+
24+
?>
25+
--EXPECT--
26+
Proxy::__isset
27+
Proxy::__get
28+
bool(false)

Zend/zend_object_handlers.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -956,25 +956,25 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
956956
uninit_error:
957957
if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
958958
if (!prop_info || (Z_PROP_FLAG_P(retval) & IS_PROP_LAZY)) {
959-
zobj = zend_lazy_object_init(zobj);
960-
if (!zobj) {
959+
zend_object *instance = zend_lazy_object_init(zobj);
960+
if (!instance) {
961961
retval = &EG(uninitialized_zval);
962962
goto exit;
963963
}
964964

965-
if (UNEXPECTED(guard)) {
965+
if (UNEXPECTED(guard && instance->ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
966966
uint32_t guard_type = (type == BP_VAR_IS) && zobj->ce->__isset
967967
? IN_ISSET : IN_GET;
968-
guard = zend_get_property_guard(zobj, name);
968+
guard = zend_get_property_guard(instance, name);
969969
if (!((*guard) & guard_type)) {
970970
(*guard) |= guard_type;
971-
retval = zend_std_read_property(zobj, name, type, cache_slot, rv);
971+
retval = zend_std_read_property(instance, name, type, cache_slot, rv);
972972
(*guard) &= ~guard_type;
973973
return retval;
974974
}
975975
}
976976

977-
return zend_std_read_property(zobj, name, type, cache_slot, rv);
977+
return zend_std_read_property(instance, name, type, cache_slot, rv);
978978
}
979979
}
980980
if (type != BP_VAR_IS) {
@@ -1013,7 +1013,7 @@ static zval *forward_write_to_lazy_object(zend_object *zobj,
10131013
return &EG(error_zval);
10141014
}
10151015

1016-
if (UNEXPECTED(guarded)) {
1016+
if (UNEXPECTED(guarded && instance->ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
10171017
uint32_t *guard = zend_get_property_guard(instance, name);
10181018
if (!((*guard) & IN_SET)) {
10191019
(*guard) |= IN_SET;

0 commit comments

Comments
 (0)