1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

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
This commit is contained in:
Arnaud Le Blanc
2024-10-10 16:39:36 +02:00
parent f086eaa7b8
commit c310be09ed
4 changed files with 74 additions and 4 deletions

4
NEWS
View File

@@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.4.2
- Core:
. Fixed bug GH-16344 (setRawValueWithoutLazyInitialization() and
skipLazyInitialization() may change initialized proxy). (Arnaud)
- DOM:
. Fixed bug GH-16906 (Reloading document can cause UAF in iterator).
(nielsdos)

View File

@@ -17,6 +17,7 @@ function test(string $name, object $obj) {
$reflector->initializeLazyObject($obj);
$reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, 'test');
var_dump($obj->a);
var_dump($obj);
}
@@ -33,9 +34,22 @@ $obj = $reflector->newLazyProxy(function () {
test('Proxy', $obj);
$real = new C('foo');
$obj = $reflector->newLazyProxy(function () use ($real) {
return $real;
});
$reflector->initializeLazyObject($obj);
$reflector->resetAsLazyProxy($real, function () {
return new C('bar');
});
$reflector->initializeLazyObject($real);
test('Nested Proxy', $obj);
?>
--EXPECTF--
# Ghost
string(4) "test"
object(C)#%d (2) {
["a"]=>
string(4) "test"
@@ -43,12 +57,27 @@ object(C)#%d (2) {
NULL
}
# Proxy
string(4) "test"
lazy proxy object(C)#%d (1) {
["instance"]=>
object(C)#%d (2) {
["a"]=>
NULL
string(4) "test"
["b"]=>
NULL
}
}
# Nested Proxy
string(4) "test"
lazy proxy object(C)#%d (1) {
["instance"]=>
lazy proxy object(C)#%d (1) {
["instance"]=>
object(C)#%d (2) {
["a"]=>
string(4) "test"
["b"]=>
NULL
}
}
}

View File

@@ -36,6 +36,19 @@ $obj = $reflector->newLazyProxy(function () {
test('Proxy', $obj);
$real = new C('foo');
$obj = $reflector->newLazyProxy(function () use ($real) {
return $real;
});
$reflector->initializeLazyObject($obj);
$reflector->resetAsLazyProxy($real, function () {
var_dump("initializer");
return new C('bar');
});
$reflector->initializeLazyObject($real);
test('Nested Proxy', $obj);
?>
--EXPECTF--
# Ghost
@@ -48,7 +61,7 @@ object(C)#%d (2) {
NULL
}
# Proxy
int(1)
int(2)
bool(true)
lazy proxy object(C)#%d (1) {
["instance"]=>
@@ -59,3 +72,19 @@ lazy proxy object(C)#%d (1) {
NULL
}
}
string(11) "initializer"
# Nested Proxy
int(2)
bool(true)
lazy proxy object(C)#%d (1) {
["instance"]=>
lazy proxy object(C)#%d (1) {
["instance"]=>
object(C)#%d (2) {
["a"]=>
int(2)
["b"]=>
NULL
}
}
}

View File

@@ -6228,6 +6228,11 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization)
RETURN_THROWS();
}
while (zend_object_is_lazy_proxy(object)
&& zend_lazy_object_initialized(object)) {
object = zend_lazy_object_get_instance(object);
}
zval *var_ptr = OBJ_PROP(object, ref->prop->offset);
bool prop_was_lazy = Z_PROP_FLAG_P(var_ptr) & IS_PROP_LAZY;
@@ -6271,7 +6276,10 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization)
RETURN_THROWS();
}
bool prop_was_lazy = (Z_PROP_FLAG_P(OBJ_PROP(object, ref->prop->offset)) & IS_PROP_LAZY);
while (zend_object_is_lazy_proxy(object)
&& zend_lazy_object_initialized(object)) {
object = zend_lazy_object_get_instance(object);
}
zval *src = &object->ce->default_properties_table[OBJ_PROP_TO_NUM(ref->prop->offset)];
zval *dst = OBJ_PROP(object, ref->prop->offset);
@@ -6286,7 +6294,7 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization)
ZVAL_COPY_PROP(dst, src);
/* Object becomes non-lazy if this was the last lazy prop */
if (prop_was_lazy && zend_object_is_lazy(object)
if (zend_object_is_lazy(object)
&& !zend_lazy_object_initialized(object)) {
if (zend_lazy_object_decr_lazy_props(object)) {
zend_lazy_object_realize(object);