Skip to content

Commit 26aefb7

Browse files
committed
Fix #69804: ::getStaticPropertyValue() throws on protected props
`ReflectionClass` allows reading of the values of private and protected constants, and also to get private and protected static methods. Therefore getting the values of private and protected static properties is also permissible, especially since `::getStaticProperties()` already allows to do so. We also allow ::setStaticPropertyValue() to modify private and protected properties, because otherwise this method is useless, as modifying public properties can be done directly.
1 parent ef2130d commit 26aefb7

File tree

5 files changed

+83
-37
lines changed

5 files changed

+83
-37
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ PHP NEWS
88
- Reflection:
99
. Fixed bug #79487 (::getStaticProperties() ignores property modifications).
1010
(cmb, Nikita)
11+
. Fixed bug #69804 ()::getStaticPropertyValue() throws on protected props).
12+
(cmb, Nikita)
1113

1214
?? ??? 2020, PHP 7.4.8
1315

ext/reflection/php_reflection.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3814,7 +3814,7 @@ ZEND_METHOD(reflection_class, getStaticProperties)
38143814
ZEND_METHOD(reflection_class, getStaticPropertyValue)
38153815
{
38163816
reflection_object *intern;
3817-
zend_class_entry *ce;
3817+
zend_class_entry *ce, *old_scope;
38183818
zend_string *name;
38193819
zval *prop, *def_value = NULL;
38203820

@@ -3827,7 +3827,12 @@ ZEND_METHOD(reflection_class, getStaticPropertyValue)
38273827
if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
38283828
return;
38293829
}
3830+
3831+
old_scope = EG(fake_scope);
3832+
EG(fake_scope) = ce;
38303833
prop = zend_std_get_static_property(ce, name, BP_VAR_IS);
3834+
EG(fake_scope) = old_scope;
3835+
38313836
if (!prop) {
38323837
if (def_value) {
38333838
ZVAL_COPY(return_value, def_value);
@@ -3847,7 +3852,7 @@ ZEND_METHOD(reflection_class, getStaticPropertyValue)
38473852
ZEND_METHOD(reflection_class, setStaticPropertyValue)
38483853
{
38493854
reflection_object *intern;
3850-
zend_class_entry *ce;
3855+
zend_class_entry *ce, *old_scope;
38513856
zend_property_info *prop_info;
38523857
zend_string *name;
38533858
zval *variable_ptr, *value;
@@ -3861,7 +3866,10 @@ ZEND_METHOD(reflection_class, setStaticPropertyValue)
38613866
if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
38623867
return;
38633868
}
3864-
variable_ptr = zend_std_get_static_property_with_info(ce, name, BP_VAR_W, &prop_info);
3869+
old_scope = EG(fake_scope);
3870+
EG(fake_scope) = ce;
3871+
variable_ptr = zend_std_get_static_property_with_info(ce, name, BP_VAR_W, &prop_info);
3872+
EG(fake_scope) = old_scope;
38653873
if (!variable_ptr) {
38663874
zend_clear_exception();
38673875
zend_throw_exception_ex(reflection_exception_ptr, 0,

ext/reflection/tests/006.phpt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,28 @@ TestDerived::testing();
8888
string(3) "pub"
8989
string(3) "pub"
9090
string(7) "updated"
91-
EXCEPTION
92-
EXCEPTION
91+
string(3) "pro"
92+
string(3) "pro"
93+
string(7) "updated"
94+
string(3) "pri"
95+
string(3) "pri"
96+
string(7) "updated"
97+
string(7) "updated"
98+
string(7) "updated"
99+
string(7) "updated"
100+
string(7) "updated"
101+
string(7) "updated"
102+
string(7) "updated"
103+
string(7) "updated"
104+
string(7) "updated"
105+
string(7) "updated"
106+
string(7) "updated"
107+
string(7) "updated"
108+
string(7) "updated"
93109
string(7) "updated"
94110
string(7) "updated"
95111
string(7) "updated"
96-
EXCEPTION
97-
EXCEPTION
98112
string(7) "updated"
99113
string(7) "updated"
100114
string(7) "updated"
101-
EXCEPTION
102-
EXCEPTION
103115
===DONE===

ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,47 @@ class B extends A {
1919

2020
echo "Retrieving static values from A:\n";
2121
$rcA = new ReflectionClass('A');
22-
var_dump($rcA->getStaticPropertyValue("privateOverridden", "default value"));
23-
var_dump($rcA->getStaticPropertyValue("\0A\0privateOverridden"));
24-
var_dump($rcA->getStaticPropertyValue("protectedOverridden", "default value"));
25-
var_dump($rcA->getStaticPropertyValue("\0*\0protectedOverridden"));
22+
var_dump($rcA->getStaticPropertyValue("privateDoesNotExist", "default value"));
23+
var_dump($rcA->getStaticPropertyValue("privateOverridden"));
24+
var_dump($rcA->getStaticPropertyValue("protectedDoesNotExist", "default value"));
25+
var_dump($rcA->getStaticPropertyValue("protectedOverridden"));
2626
var_dump($rcA->getStaticPropertyValue("publicOverridden"));
2727

2828
echo "\nRetrieving static values from B:\n";
2929
$rcB = new ReflectionClass('B');
30-
var_dump($rcB->getStaticPropertyValue("\0A\0privateOverridden"));
31-
var_dump($rcB->getStaticPropertyValue("\0B\0privateOverridden"));
32-
var_dump($rcB->getStaticPropertyValue("\0*\0protectedOverridden"));
30+
var_dump($rcB->getStaticPropertyValue("privateOverridden"));
31+
var_dump($rcB->getStaticPropertyValue("protectedOverridden"));
3332
var_dump($rcB->getStaticPropertyValue("publicOverridden"));
3433

3534
echo "\nRetrieving non-existent values from A with no default value:\n";
3635
try {
37-
var_dump($rcA->getStaticPropertyValue("protectedOverridden"));
36+
var_dump($rcA->getStaticPropertyValue("protectedDoesNotExist"));
3837
echo "you should not see this";
3938
} catch (Exception $e) {
4039
echo $e->getMessage() . "\n";
4140
}
4241

4342
try {
44-
var_dump($rcA->getStaticPropertyValue("privateOverridden"));
43+
var_dump($rcA->getStaticPropertyValue("privateDoesNotExist"));
4544
echo "you should not see this";
4645
} catch (Exception $e) {
4746
echo $e->getMessage() . "\n";
4847
}
4948

5049
?>
51-
--EXPECTF--
50+
--EXPECT--
5251
Retrieving static values from A:
5352
string(13) "default value"
53+
string(16) "original private"
54+
string(13) "default value"
55+
string(18) "original protected"
56+
string(15) "original public"
57+
58+
Retrieving static values from B:
59+
string(15) "changed private"
60+
string(17) "changed protected"
61+
string(14) "changed public"
5462

55-
Fatal error: Uncaught ReflectionException: Class A does not have a property named in %s:%d
56-
Stack trace:
57-
#0 %s(%d): ReflectionClass->getStaticPropertyValue('\x00A\x00privateOverr...')
58-
#1 {main}
59-
thrown in %s on line %d
63+
Retrieving non-existent values from A with no default value:
64+
Class A does not have a property named protectedDoesNotExist
65+
Class A does not have a property named privateDoesNotExist

ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,59 @@ class B extends A {
1919

2020
echo "Set static values in A:\n";
2121
$rcA = new ReflectionClass('A');
22-
$rcA->setStaticPropertyValue("\0A\0privateOverridden", "new value 1");
23-
$rcA->setStaticPropertyValue("\0*\0protectedOverridden", "new value 2");
22+
$rcA->setStaticPropertyValue("privateOverridden", "new value 1");
23+
$rcA->setStaticPropertyValue("protectedOverridden", "new value 2");
2424
$rcA->setStaticPropertyValue("publicOverridden", "new value 3");
2525
print_r($rcA->getStaticProperties());
2626

2727
echo "\nSet static values in B:\n";
2828
$rcB = new ReflectionClass('B');
29-
$rcB->setStaticPropertyValue("\0A\0privateOverridden", "new value 4");
30-
$rcB->setStaticPropertyValue("\0B\0privateOverridden", "new value 5");
31-
$rcB->setStaticPropertyValue("\0*\0protectedOverridden", "new value 6");
29+
$rcB->setStaticPropertyValue("privateOverridden", "new value 4");
30+
$rcB->setStaticPropertyValue("privateOverridden", "new value 5");
31+
$rcB->setStaticPropertyValue("protectedOverridden", "new value 6");
3232
$rcB->setStaticPropertyValue("publicOverridden", "new value 7");
3333
print_r($rcA->getStaticProperties());
3434
print_r($rcB->getStaticProperties());
3535

3636
echo "\nSet non-existent values from A with no default value:\n";
3737
try {
38-
var_dump($rcA->setStaticPropertyValue("protectedOverridden", "new value 8"));
38+
var_dump($rcA->setStaticPropertyValue("protectedDoesNotExist", "new value 8"));
3939
echo "you should not see this";
4040
} catch (Exception $e) {
4141
echo $e->getMessage() . "\n";
4242
}
4343

4444
try {
45-
var_dump($rcA->setStaticPropertyValue("privateOverridden", "new value 9"));
45+
var_dump($rcA->setStaticPropertyValue("privateDoesNotExist", "new value 9"));
4646
echo "you should not see this";
4747
} catch (Exception $e) {
4848
echo $e->getMessage() . "\n";
4949
}
5050

5151
?>
52-
--EXPECTF--
52+
--EXPECT--
5353
Set static values in A:
54+
Array
55+
(
56+
[privateOverridden] => new value 1
57+
[protectedOverridden] => new value 2
58+
[publicOverridden] => new value 3
59+
)
5460

55-
Fatal error: Uncaught ReflectionException: Class A does not have a property named in %s:%d
56-
Stack trace:
57-
#0 %s(%d): ReflectionClass->setStaticPropertyValue('\x00A\x00privateOverr...', 'new value 1')
58-
#1 {main}
59-
thrown in %s on line %d
61+
Set static values in B:
62+
Array
63+
(
64+
[privateOverridden] => new value 1
65+
[protectedOverridden] => new value 2
66+
[publicOverridden] => new value 3
67+
)
68+
Array
69+
(
70+
[privateOverridden] => new value 5
71+
[protectedOverridden] => new value 6
72+
[publicOverridden] => new value 7
73+
)
74+
75+
Set non-existent values from A with no default value:
76+
Class A does not have a property named protectedDoesNotExist
77+
Class A does not have a property named privateDoesNotExist

0 commit comments

Comments
 (0)