Skip to content

Commit c310be0

Browse files
committed
Fix setRawValueWithoutLazyInitialization() and skipLazyInitialization() on initialized proxy
Normally, accesses to properties marked as lazy trigger the object's initialization, or forward to a real instance if the object is an initialized proxy. The purpose of ReflectionProperty::setRawValueWithoutLazyInitialization() and ReflectionProperty::skipLazyInitialization() is to bypass auto-initialization, so that some properties can be initialized without triggering initialization. However, when the object is an initialized proxy, these methods would unexpectedly update the proxy. Here I make sure that these methods have an effect on the real instance, when the object is an initialized proxy. Fixes GH-16344
1 parent f086eaa commit c310be0

File tree

4 files changed

+74
-4
lines changed

4 files changed

+74
-4
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.4.2
44

5+
- Core:
6+
. Fixed bug GH-16344 (setRawValueWithoutLazyInitialization() and
7+
skipLazyInitialization() may change initialized proxy). (Arnaud)
8+
59
- DOM:
610
. Fixed bug GH-16906 (Reloading document can cause UAF in iterator).
711
(nielsdos)

Zend/tests/lazy_objects/setRawValueWithoutLazyInitialization_initialized.phpt

+30-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function test(string $name, object $obj) {
1717
$reflector->initializeLazyObject($obj);
1818
$reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'test');
1919

20+
var_dump($obj->a);
2021
var_dump($obj);
2122
}
2223

@@ -33,22 +34,50 @@ $obj = $reflector->newLazyProxy(function () {
3334

3435
test('Proxy', $obj);
3536

37+
$real = new C('foo');
38+
$obj = $reflector->newLazyProxy(function () use ($real) {
39+
return $real;
40+
});
41+
$reflector->initializeLazyObject($obj);
42+
$reflector->resetAsLazyProxy($real, function () {
43+
return new C('bar');
44+
});
45+
$reflector->initializeLazyObject($real);
46+
47+
test('Nested Proxy', $obj);
48+
3649
?>
3750
--EXPECTF--
3851
# Ghost
52+
string(4) "test"
3953
object(C)#%d (2) {
4054
["a"]=>
4155
string(4) "test"
4256
["b"]=>
4357
NULL
4458
}
4559
# Proxy
60+
string(4) "test"
4661
lazy proxy object(C)#%d (1) {
4762
["instance"]=>
4863
object(C)#%d (2) {
4964
["a"]=>
50-
NULL
65+
string(4) "test"
5166
["b"]=>
5267
NULL
5368
}
5469
}
70+
# Nested Proxy
71+
string(4) "test"
72+
lazy proxy object(C)#%d (1) {
73+
["instance"]=>
74+
lazy proxy object(C)#%d (1) {
75+
["instance"]=>
76+
object(C)#%d (2) {
77+
["a"]=>
78+
string(4) "test"
79+
["b"]=>
80+
NULL
81+
}
82+
}
83+
}

Zend/tests/lazy_objects/skipLazyInitialization_initialized_object.phpt

+30-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,19 @@ $obj = $reflector->newLazyProxy(function () {
3636

3737
test('Proxy', $obj);
3838

39+
$real = new C('foo');
40+
$obj = $reflector->newLazyProxy(function () use ($real) {
41+
return $real;
42+
});
43+
$reflector->initializeLazyObject($obj);
44+
$reflector->resetAsLazyProxy($real, function () {
45+
var_dump("initializer");
46+
return new C('bar');
47+
});
48+
$reflector->initializeLazyObject($real);
49+
50+
test('Nested Proxy', $obj);
51+
3952
?>
4053
--EXPECTF--
4154
# Ghost
@@ -48,7 +61,7 @@ object(C)#%d (2) {
4861
NULL
4962
}
5063
# Proxy
51-
int(1)
64+
int(2)
5265
bool(true)
5366
lazy proxy object(C)#%d (1) {
5467
["instance"]=>
@@ -59,3 +72,19 @@ lazy proxy object(C)#%d (1) {
5972
NULL
6073
}
6174
}
75+
string(11) "initializer"
76+
# Nested Proxy
77+
int(2)
78+
bool(true)
79+
lazy proxy object(C)#%d (1) {
80+
["instance"]=>
81+
lazy proxy object(C)#%d (1) {
82+
["instance"]=>
83+
object(C)#%d (2) {
84+
["a"]=>
85+
int(2)
86+
["b"]=>
87+
NULL
88+
}
89+
}
90+
}

ext/reflection/php_reflection.c

+10-2
Original file line numberDiff line numberDiff line change
@@ -6228,6 +6228,11 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization)
62286228
RETURN_THROWS();
62296229
}
62306230

6231+
while (zend_object_is_lazy_proxy(object)
6232+
&& zend_lazy_object_initialized(object)) {
6233+
object = zend_lazy_object_get_instance(object);
6234+
}
6235+
62316236
zval *var_ptr = OBJ_PROP(object, ref->prop->offset);
62326237
bool prop_was_lazy = Z_PROP_FLAG_P(var_ptr) & IS_PROP_LAZY;
62336238

@@ -6271,7 +6276,10 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization)
62716276
RETURN_THROWS();
62726277
}
62736278

6274-
bool prop_was_lazy = (Z_PROP_FLAG_P(OBJ_PROP(object, ref->prop->offset)) & IS_PROP_LAZY);
6279+
while (zend_object_is_lazy_proxy(object)
6280+
&& zend_lazy_object_initialized(object)) {
6281+
object = zend_lazy_object_get_instance(object);
6282+
}
62756283

62766284
zval *src = &object->ce->default_properties_table[OBJ_PROP_TO_NUM(ref->prop->offset)];
62776285
zval *dst = OBJ_PROP(object, ref->prop->offset);
@@ -6286,7 +6294,7 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization)
62866294
ZVAL_COPY_PROP(dst, src);
62876295

62886296
/* Object becomes non-lazy if this was the last lazy prop */
6289-
if (prop_was_lazy && zend_object_is_lazy(object)
6297+
if (zend_object_is_lazy(object)
62906298
&& !zend_lazy_object_initialized(object)) {
62916299
if (zend_lazy_object_decr_lazy_props(object)) {
62926300
zend_lazy_object_realize(object);

0 commit comments

Comments
 (0)