Skip to content

Commit 17e783e

Browse files
committed
Fix GH-24147: Reflection name/class can be modified by compound assignment
1 parent 8db886e commit 17e783e

4 files changed

Lines changed: 67 additions & 2 deletions

File tree

‎NEWS‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ PHP NEWS
8181
. Fixed a heap over-read in the interactive shell prompt when cli.prompt is
8282
set to an empty string. (Ilia Alshanetsky)
8383

84+
- Reflection:
85+
. Fixed bug GH-24147 (ReflectionProperty class and name properties can be
86+
modified through compound assignment or by reference). (lazerg)
87+
8488
- Session:
8589
. Fixed session_start() continuing after a failed create_sid() when
8690
session.use_strict_mode rejects the supplied ID. (Ilia Alshanetsky)

‎UPGRADING‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ PHP 8.7 UPGRADE NOTES
2727
not present in the result set. It previously reported the condition
2828
through PDO::ATTR_ERRMODE and returned false.
2929

30+
- Reflection:
31+
. Modifying the $name or $class property of a Reflection object through
32+
compound assignment, increment/decrement or by reference now throws a
33+
ReflectionException, like a plain assignment already did.
34+
3035
- Standard:
3136
. The number of filters that can be chained in a php://filter URL is limited
3237
to 16 by default. Set the stream context option max_filter_count to change

‎ext/reflection/php_reflection.c‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7936,11 +7936,16 @@ ZEND_METHOD(ReflectionFiber, getCallable)
79367936
RETURN_COPY(&fiber->fci.function_name);
79377937
}
79387938

7939+
static bool reflection_is_read_only_property(zend_object *object, zend_string *name)
7940+
{
7941+
return zend_hash_exists(&object->ce->properties_info, name)
7942+
&& (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_NAME)) || zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_CLASS)));
7943+
}
7944+
79397945
/* {{{ _reflection_write_property */
79407946
static zval *_reflection_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
79417947
{
7942-
if (zend_hash_exists(&object->ce->properties_info, name)
7943-
&& (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_NAME)) || zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_CLASS))))
7948+
if (reflection_is_read_only_property(object, name))
79447949
{
79457950
zend_throw_exception_ex(reflection_exception_ptr, 0,
79467951
"Cannot set read-only property %pS::$%pS", object->ce->name, name);
@@ -7951,6 +7956,17 @@ static zval *_reflection_write_property(zend_object *object, zend_string *name,
79517956
}
79527957
/* }}} */
79537958

7959+
static zval *_reflection_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot)
7960+
{
7961+
if (reflection_is_read_only_property(object, name)) {
7962+
zend_throw_exception_ex(reflection_exception_ptr, 0,
7963+
"Cannot set read-only property %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
7964+
return &EG(error_zval);
7965+
}
7966+
7967+
return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
7968+
}
7969+
79547970
ZEND_METHOD(ReflectionConstant, __construct)
79557971
{
79567972
zend_string *name;
@@ -8172,6 +8188,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
81728188
reflection_object_handlers.free_obj = reflection_free_objects_storage;
81738189
reflection_object_handlers.clone_obj = NULL;
81748190
reflection_object_handlers.write_property = _reflection_write_property;
8191+
reflection_object_handlers.get_property_ptr_ptr = _reflection_get_property_ptr_ptr;
81758192
reflection_object_handlers.get_gc = reflection_get_gc;
81768193

81778194
reflection_exception_ptr = register_class_ReflectionException(zend_ce_exception);

‎ext/reflection/tests/gh24147.phpt‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
GH-24147 (ReflectionProperty class and name properties can be changed)
3+
--FILE--
4+
<?php
5+
6+
class B {
7+
public string $x;
8+
}
9+
10+
$prop = new ReflectionProperty('B', 'x');
11+
12+
try {
13+
$prop->class .= 'Z';
14+
} catch (ReflectionException $e) {
15+
echo $e->getMessage(), "\n";
16+
}
17+
18+
try {
19+
$prop->name++;
20+
} catch (ReflectionException $e) {
21+
echo $e->getMessage(), "\n";
22+
}
23+
24+
try {
25+
$ref = &$prop->name;
26+
$ref = 'y';
27+
} catch (ReflectionException $e) {
28+
echo $e->getMessage(), "\n";
29+
}
30+
31+
var_dump($prop->class, $prop->name);
32+
33+
?>
34+
--EXPECT--
35+
Cannot set read-only property ReflectionProperty::$class
36+
Cannot set read-only property ReflectionProperty::$name
37+
Cannot set read-only property ReflectionProperty::$name
38+
string(1) "B"
39+
string(1) "x"

0 commit comments

Comments
 (0)