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:
4
NEWS
4
NEWS
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user