Skip to content

Commit 83b7358

Browse files
committed
Fix GH-21478: Forward read_property to real instance for initialized lazy proxies
When an initialized lazy proxy has __get/__isset, zend_std_read_property() was calling the magic method on the proxy itself before forwarding to the real instance at uninit_error. This caused double invocations: __get fired on both the real instance and the proxy. For pure reads (BP_VAR_R, BP_VAR_IS), forward directly to the real instance before attempting magic methods on the proxy. Write contexts (BP_VAR_W/RW) are excluded because read_property with those types is used as a fallback from get_property_ptr_ptr for reference operations involving __get. Closes GH-21478
1 parent 30b2d77 commit 83b7358

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

Zend/tests/lazy_objects/gh18038-004.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ var_dump($real->prop);
3636
--EXPECTF--
3737
init
3838
string(19) "RealInstance::__get"
39-
string(12) "Proxy::__get"
4039

4140
Warning: Undefined property: RealInstance::$prop in %s on line %d
4241
NULL

Zend/tests/lazy_objects/gh18038-007.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,5 @@ var_dump(isset($real->prop['']));
3636
--EXPECT--
3737
init
3838
string(21) "RealInstance::__isset"
39-
string(14) "Proxy::__isset"
4039
bool(false)
4140
bool(false)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
GH-21478 (Property access on lazy proxy may invoke magic method despite real instance guards)
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public $_;
8+
9+
public function __get($name) {
10+
global $proxy;
11+
printf("__get(\$%s) on %s\n", $name, $this::class);
12+
return $proxy->{$name};
13+
}
14+
}
15+
16+
class Bar extends Foo {}
17+
18+
$rc = new ReflectionClass(Bar::class);
19+
$proxy = $rc->newLazyProxy(function () {
20+
echo "Init\n";
21+
return new Foo();
22+
});
23+
24+
$real = $rc->initializeLazyObject($proxy);
25+
$real->x;
26+
27+
?>
28+
--EXPECTF--
29+
Init
30+
__get($x) on Foo
31+
32+
Warning: Undefined property: Foo::$x in %s on line %d

Zend/zend_object_handlers.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,13 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
893893

894894
retval = &EG(uninitialized_zval);
895895

896+
if (UNEXPECTED(zend_object_is_lazy_proxy(zobj)
897+
&& zend_lazy_object_initialized(zobj)
898+
&& (type == BP_VAR_R || type == BP_VAR_IS))) {
899+
zend_object *instance = zend_lazy_object_get_instance(zobj);
900+
return zend_std_read_property(instance, name, type, cache_slot, rv);
901+
}
902+
896903
/* magic isset */
897904
if ((type == BP_VAR_IS) && zobj->ce->__isset) {
898905
zval tmp_result;

0 commit comments

Comments
 (0)