Skip to content

Commit 83056c8

Browse files
committed
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4: Real instance of lazy proxy may have less magic methods
2 parents 1e81a9e + de26827 commit 83056c8

File tree

7 files changed

+150
-8
lines changed

7 files changed

+150
-8
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ PHP NEWS
1111
(alexandre-daubois)
1212
. Fixed bug GH-20657 (Assertion failure in zend_lazy_object_get_info triggered
1313
by setRawValueWithoutLazyInitialization() and newLazyGhost()). (Arnaud)
14+
. Fixed bug GH-20504 (Assertion failure in zend_get_property_guard when
15+
accessing properties on Reflection LazyProxy via isset()). (Arnaud)
1416

1517
- DOM:
1618
. Fixed bug GH-21077 (Accessing Dom\Node::baseURI can throw TypeError).
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - isset
3+
--CREDITS--
4+
vi3tL0u1s
5+
--FILE--
6+
<?php
7+
8+
class RealInstance {
9+
public $_;
10+
}
11+
class Proxy extends RealInstance {
12+
public function __isset($name) {
13+
return isset($this->$name['']);
14+
}
15+
}
16+
$rc = new ReflectionClass(Proxy::class);
17+
$obj = $rc->newLazyProxy(function () {
18+
return new RealInstance;
19+
});
20+
var_dump(isset($obj->name['']));
21+
22+
?>
23+
--EXPECT--
24+
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)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - unset
3+
--FILE--
4+
<?php
5+
6+
class RealInstance {
7+
public $_;
8+
}
9+
class Proxy extends RealInstance {
10+
public function __unset($name) {
11+
unset($this->$name);
12+
}
13+
}
14+
$rc = new ReflectionClass(Proxy::class);
15+
$obj = $rc->newLazyProxy(function () {
16+
return new RealInstance;
17+
});
18+
unset($obj->name);
19+
20+
var_dump($obj);
21+
22+
?>
23+
--EXPECTF--
24+
lazy proxy object(Proxy)#%d (1) {
25+
["instance"]=>
26+
object(RealInstance)#%d (1) {
27+
["_"]=>
28+
NULL
29+
}
30+
}

Zend/zend_object_handlers.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -960,25 +960,27 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
960960
uninit_error:
961961
if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
962962
if (!prop_info || (Z_PROP_FLAG_P(retval) & IS_PROP_LAZY)) {
963-
zobj = zend_lazy_object_init(zobj);
964-
if (!zobj) {
963+
zend_object *instance = zend_lazy_object_init(zobj);
964+
if (!instance) {
965965
retval = &EG(uninitialized_zval);
966966
goto exit;
967967
}
968968

969-
if (UNEXPECTED(guard)) {
969+
if (UNEXPECTED(guard && (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS))) {
970+
/* Find which guard was used on zobj, so we can set the same
971+
* guard on instance. */
970972
uint32_t guard_type = (type == BP_VAR_IS) && zobj->ce->__isset
971973
? IN_ISSET : IN_GET;
972-
guard = zend_get_property_guard(zobj, name);
974+
guard = zend_get_property_guard(instance, name);
973975
if (!((*guard) & guard_type)) {
974976
(*guard) |= guard_type;
975-
retval = zend_std_read_property(zobj, name, type, cache_slot, rv);
977+
retval = zend_std_read_property(instance, name, type, cache_slot, rv);
976978
(*guard) &= ~guard_type;
977979
return retval;
978980
}
979981
}
980982

981-
return zend_std_read_property(zobj, name, type, cache_slot, rv);
983+
return zend_std_read_property(instance, name, type, cache_slot, rv);
982984
}
983985
}
984986
if (type != BP_VAR_IS) {
@@ -1017,7 +1019,7 @@ static zval *forward_write_to_lazy_object(zend_object *zobj,
10171019
return &EG(error_zval);
10181020
}
10191021

1020-
if (UNEXPECTED(guarded)) {
1022+
if (UNEXPECTED(guarded && (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS))) {
10211023
uint32_t *guard = zend_get_property_guard(instance, name);
10221024
if (!((*guard) & IN_SET)) {
10231025
(*guard) |= IN_SET;
@@ -1601,7 +1603,7 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void
16011603
return;
16021604
}
16031605

1604-
if (UNEXPECTED(guard)) {
1606+
if (UNEXPECTED(guard && zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
16051607
guard = zend_get_property_guard(zobj, name);
16061608
if (!((*guard) & IN_UNSET)) {
16071609
(*guard) |= IN_UNSET;

0 commit comments

Comments
 (0)