Skip to content

Commit c84bf88

Browse files
committed
Fix assertion failure when &__get forwards through initialized lazy proxy
When read_property forwards to the real instance and gets back &EG(uninitialized_zval), return rv with ZVAL_NULL instead. This preserves the invariant that read_property won't return the uninitialized sentinel when get_property_ptr_ptr returned NULL.
1 parent 9599791 commit c84bf88

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
GH-21478: No assertion failure when &__get forwards through initialized lazy proxy
3+
--FILE--
4+
<?php
5+
class Foo {
6+
public $_;
7+
8+
public function &__get($name) {
9+
global $proxy;
10+
printf("%s(\$%s) on %s\n", __METHOD__, $name, $this::class);
11+
return $proxy->{$name};
12+
}
13+
}
14+
15+
class Bar extends Foo {}
16+
17+
$rc = new ReflectionClass(Bar::class);
18+
$proxy = $rc->newLazyProxy(function () {
19+
echo "Init\n";
20+
return new Foo();
21+
});
22+
23+
$real = $rc->initializeLazyObject($proxy);
24+
$a = &$real->x;
25+
var_dump($a);
26+
?>
27+
--EXPECTF--
28+
Init
29+
Foo::__get($x) on Foo
30+
31+
Warning: Undefined property: Foo::$x in %s on line %d
32+
NULL

Zend/zend_object_handlers.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,12 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int
898898
uint32_t guard_type = ((type == BP_VAR_IS) && zobj->ce->__isset)
899899
? IN_ISSET : IN_GET;
900900
if ((*instance_guard) & guard_type) {
901-
return zend_std_read_property(instance, name, type, cache_slot, rv);
901+
retval = zend_std_read_property(instance, name, type, cache_slot, rv);
902+
if (retval == &EG(uninitialized_zval)) {
903+
ZVAL_NULL(rv);
904+
retval = rv;
905+
}
906+
return retval;
902907
}
903908
}
904909
}

0 commit comments

Comments
 (0)