Skip to content

Commit 7638653

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix ReflectionProperty::getRawValue() and related methods for properties overridden with hooks
2 parents 35be6d0 + 24b191a commit 7638653

File tree

3 files changed

+238
-42
lines changed

3 files changed

+238
-42
lines changed

Zend/tests/lazy_objects/skipLazyInitialization.phpt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,10 @@ getValue(): string(5) "value"
198198
## Property [ public static $static = 'static' ]
199199

200200
skipInitializerForProperty():
201-
ReflectionException: Can not use skipLazyInitialization on static property B::$static
201+
ReflectionException: Can not use skipLazyInitialization on static property A::$static
202202

203203
setRawValueWithoutLazyInitialization():
204-
ReflectionException: Can not use setRawValueWithoutLazyInitialization on static property B::$static
204+
ReflectionException: Can not use setRawValueWithoutLazyInitialization on static property A::$static
205205

206206
## Property [ public $noDefault = NULL ]
207207

@@ -238,10 +238,10 @@ getValue(): string(5) "value"
238238
## Property [ public $virtual ]
239239

240240
skipInitializerForProperty():
241-
ReflectionException: Can not use skipLazyInitialization on virtual property B::$virtual
241+
ReflectionException: Can not use skipLazyInitialization on virtual property A::$virtual
242242

243243
setRawValueWithoutLazyInitialization():
244-
ReflectionException: Can not use setRawValueWithoutLazyInitialization on virtual property B::$virtual
244+
ReflectionException: Can not use setRawValueWithoutLazyInitialization on virtual property A::$virtual
245245

246246
## Property [ $dynamicProp ]
247247

@@ -295,10 +295,10 @@ getValue(): string(5) "value"
295295
## Property [ public static $static = 'static' ]
296296

297297
skipInitializerForProperty():
298-
ReflectionException: Can not use skipLazyInitialization on static property B::$static
298+
ReflectionException: Can not use skipLazyInitialization on static property A::$static
299299

300300
setRawValueWithoutLazyInitialization():
301-
ReflectionException: Can not use setRawValueWithoutLazyInitialization on static property B::$static
301+
ReflectionException: Can not use setRawValueWithoutLazyInitialization on static property A::$static
302302

303303
## Property [ public $noDefault = NULL ]
304304

@@ -335,10 +335,10 @@ getValue(): string(5) "value"
335335
## Property [ public $virtual ]
336336

337337
skipInitializerForProperty():
338-
ReflectionException: Can not use skipLazyInitialization on virtual property B::$virtual
338+
ReflectionException: Can not use skipLazyInitialization on virtual property A::$virtual
339339

340340
setRawValueWithoutLazyInitialization():
341-
ReflectionException: Can not use setRawValueWithoutLazyInitialization on virtual property B::$virtual
341+
ReflectionException: Can not use setRawValueWithoutLazyInitialization on virtual property A::$virtual
342342

343343
## Property [ $dynamicProp ]
344344

ext/reflection/php_reflection.c

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5878,6 +5878,19 @@ ZEND_METHOD(ReflectionProperty, setValue)
58785878
}
58795879
/* }}} */
58805880

5881+
/* Return the property info being used when accessing 'ref->prop' from scope
5882+
* 'scope' on 'object'. The result may be different from 'ref->prop' when the
5883+
* property is overridden on 'object' and was not private in 'scope'.
5884+
* The effective prop may add hooks or change flags. */
5885+
static zend_property_info *reflection_property_get_effective_prop(
5886+
property_reference *ref, zend_class_entry *scope, zend_object *object) {
5887+
zend_property_info *prop = ref->prop;
5888+
if (scope != object->ce && !(prop && (prop->flags & ZEND_ACC_PRIVATE))) {
5889+
prop = zend_hash_find_ptr(&object->ce->properties_info, ref->unmangled_name);
5890+
}
5891+
return prop;
5892+
}
5893+
58815894
ZEND_METHOD(ReflectionProperty, getRawValue)
58825895
{
58835896
reflection_object *intern;
@@ -5890,17 +5903,20 @@ ZEND_METHOD(ReflectionProperty, getRawValue)
58905903

58915904
GET_REFLECTION_OBJECT_PTR(ref);
58925905

5893-
if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5894-
_DO_THROW("May not use getRawValue on static properties");
5906+
if (!instanceof_function(Z_OBJCE_P(object), intern->ce)) {
5907+
_DO_THROW("Given object is not an instance of the class this property was declared in");
58955908
RETURN_THROWS();
58965909
}
58975910

5898-
if (!instanceof_function(Z_OBJCE_P(object), intern->ce)) {
5899-
_DO_THROW("Given object is not an instance of the class this property was declared in");
5911+
zend_property_info *prop = reflection_property_get_effective_prop(ref,
5912+
intern->ce, Z_OBJ_P(object));
5913+
5914+
if (UNEXPECTED(prop && (prop->flags & ZEND_ACC_STATIC))) {
5915+
_DO_THROW("May not use getRawValue on static properties");
59005916
RETURN_THROWS();
59015917
}
59025918

5903-
if (!ref->prop || !ref->prop->hooks || !ref->prop->hooks[ZEND_PROPERTY_HOOK_GET]) {
5919+
if (!prop || !prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_GET]) {
59045920
zval rv;
59055921
zval *member_p = zend_read_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, 0, &rv);
59065922

@@ -5913,17 +5929,19 @@ ZEND_METHOD(ReflectionProperty, getRawValue)
59135929
RETURN_COPY_VALUE(member_p);
59145930
}
59155931
} else {
5916-
zend_function *func = zend_get_property_hook_trampoline(ref->prop, ZEND_PROPERTY_HOOK_GET, ref->unmangled_name);
5932+
zend_function *func = zend_get_property_hook_trampoline(prop, ZEND_PROPERTY_HOOK_GET, ref->unmangled_name);
59175933
zend_call_known_instance_method_with_0_params(func, Z_OBJ_P(object), return_value);
59185934
}
59195935
}
59205936

5921-
static void reflection_property_set_raw_value(property_reference *ref, reflection_object *intern, zend_object *object, zval *value)
5937+
static void reflection_property_set_raw_value(zend_property_info *prop,
5938+
zend_string *unmangled_name, reflection_object *intern,
5939+
zend_object *object, zval *value)
59225940
{
5923-
if (!ref->prop || !ref->prop->hooks || !ref->prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
5924-
zend_update_property_ex(intern->ce, object, ref->unmangled_name, value);
5941+
if (!prop || !prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
5942+
zend_update_property_ex(intern->ce, object, unmangled_name, value);
59255943
} else {
5926-
zend_function *func = zend_get_property_hook_trampoline(ref->prop, ZEND_PROPERTY_HOOK_SET, ref->unmangled_name);
5944+
zend_function *func = zend_get_property_hook_trampoline(prop, ZEND_PROPERTY_HOOK_SET, unmangled_name);
59275945
zend_call_known_instance_method_with_1_params(func, object, NULL, value);
59285946
}
59295947
}
@@ -5937,55 +5955,59 @@ ZEND_METHOD(ReflectionProperty, setRawValue)
59375955

59385956
GET_REFLECTION_OBJECT_PTR(ref);
59395957

5940-
if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5941-
_DO_THROW("May not use setRawValue on static properties");
5958+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oz", &object, &value) == FAILURE) {
59425959
RETURN_THROWS();
59435960
}
59445961

5945-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oz", &object, &value) == FAILURE) {
5962+
zend_property_info *prop = reflection_property_get_effective_prop(ref,
5963+
intern->ce, Z_OBJ_P(object));
5964+
5965+
if (UNEXPECTED(prop && (prop->flags & ZEND_ACC_STATIC))) {
5966+
_DO_THROW("May not use setRawValue on static properties");
59465967
RETURN_THROWS();
59475968
}
59485969

5949-
reflection_property_set_raw_value(ref, intern, Z_OBJ_P(object), value);
5970+
reflection_property_set_raw_value(prop, ref->unmangled_name, intern, Z_OBJ_P(object), value);
59505971
}
59515972

5952-
static zend_result reflection_property_check_lazy_compatible(reflection_object *intern,
5953-
property_reference *ref, zend_object *object, const char *method)
5973+
static zend_result reflection_property_check_lazy_compatible(
5974+
zend_property_info *prop, zend_string *unmangled_name,
5975+
reflection_object *intern, zend_object *object, const char *method)
59545976
{
5955-
if (!ref->prop) {
5977+
if (!prop) {
59565978
zend_throw_exception_ex(reflection_exception_ptr, 0,
59575979
"Can not use %s on dynamic property %s::$%s",
59585980
method, ZSTR_VAL(intern->ce->name),
5959-
ZSTR_VAL(ref->unmangled_name));
5981+
ZSTR_VAL(unmangled_name));
59605982
return FAILURE;
59615983
}
59625984

5963-
if (ref->prop->flags & ZEND_ACC_STATIC) {
5985+
if (prop->flags & ZEND_ACC_STATIC) {
59645986
zend_throw_exception_ex(reflection_exception_ptr, 0,
59655987
"Can not use %s on static property %s::$%s",
5966-
method, ZSTR_VAL(intern->ce->name),
5967-
ZSTR_VAL(ref->unmangled_name));
5988+
method, ZSTR_VAL(prop->ce->name),
5989+
ZSTR_VAL(unmangled_name));
59685990
return FAILURE;
59695991
}
59705992

5971-
if (ref->prop->flags & ZEND_ACC_VIRTUAL) {
5993+
if (prop->flags & ZEND_ACC_VIRTUAL) {
59725994
zend_throw_exception_ex(reflection_exception_ptr, 0,
59735995
"Can not use %s on virtual property %s::$%s",
5974-
method, ZSTR_VAL(intern->ce->name),
5975-
ZSTR_VAL(ref->unmangled_name));
5996+
method, ZSTR_VAL(prop->ce->name),
5997+
ZSTR_VAL(unmangled_name));
59765998
return FAILURE;
59775999
}
59786000

59796001
if (UNEXPECTED(object->handlers->write_property != zend_std_write_property)) {
59806002
if (!zend_class_can_be_lazy(object->ce)) {
59816003
zend_throw_exception_ex(reflection_exception_ptr, 0,
59826004
"Can not use %s on internal class %s",
5983-
method, ZSTR_VAL(intern->ce->name));
6005+
method, ZSTR_VAL(object->ce->name));
59846006
return FAILURE;
59856007
}
59866008
}
59876009

5988-
ZEND_ASSERT(IS_VALID_PROPERTY_OFFSET(ref->prop->offset));
6010+
ZEND_ASSERT(IS_VALID_PROPERTY_OFFSET(prop->offset));
59896011

59906012
return SUCCESS;
59916013
}
@@ -6005,23 +6027,27 @@ ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization)
60056027
Z_PARAM_ZVAL(value)
60066028
} ZEND_PARSE_PARAMETERS_END();
60076029

6008-
if (reflection_property_check_lazy_compatible(intern, ref, object,
6009-
"setRawValueWithoutLazyInitialization") == FAILURE) {
6010-
RETURN_THROWS();
6011-
}
6012-
60136030
while (zend_object_is_lazy_proxy(object)
60146031
&& zend_lazy_object_initialized(object)) {
60156032
object = zend_lazy_object_get_instance(object);
60166033
}
60176034

6018-
zval *var_ptr = OBJ_PROP(object, ref->prop->offset);
6035+
zend_property_info *prop = reflection_property_get_effective_prop(ref,
6036+
intern->ce, object);
6037+
6038+
if (reflection_property_check_lazy_compatible(prop, ref->unmangled_name,
6039+
intern, object, "setRawValueWithoutLazyInitialization") == FAILURE) {
6040+
RETURN_THROWS();
6041+
}
6042+
6043+
zval *var_ptr = OBJ_PROP(object, prop->offset);
60196044
bool prop_was_lazy = Z_PROP_FLAG_P(var_ptr) & IS_PROP_LAZY;
60206045

60216046
/* Do not trigger initialization */
60226047
Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_LAZY;
60236048

6024-
reflection_property_set_raw_value(ref, intern, object, value);
6049+
reflection_property_set_raw_value(prop, ref->unmangled_name, intern, object,
6050+
value);
60256051

60266052
/* Mark property as lazy again if an exception prevented update */
60276053
if (EG(exception) && prop_was_lazy && Z_TYPE_P(var_ptr) == IS_UNDEF
@@ -6053,7 +6079,8 @@ ZEND_METHOD(ReflectionProperty, skipLazyInitialization)
60536079
Z_PARAM_OBJ_OF_CLASS(object, intern->ce)
60546080
} ZEND_PARSE_PARAMETERS_END();
60556081

6056-
if (reflection_property_check_lazy_compatible(intern, ref, object,
6082+
if (reflection_property_check_lazy_compatible(ref->prop,
6083+
ref->unmangled_name, intern, object,
60576084
"skipLazyInitialization") == FAILURE) {
60586085
RETURN_THROWS();
60596086
}

0 commit comments

Comments
 (0)