From 26aefb750a614391cdb8ee3f63d66f46ed57bd55 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 15 Apr 2020 15:15:21 +0200 Subject: 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. --- ext/reflection/php_reflection.c | 14 +++++-- ext/reflection/tests/006.phpt | 24 +++++++++--- ...ReflectionClass_getStaticPropertyValue_001.phpt | 36 ++++++++++-------- ...ReflectionClass_setStaticPropertyValue_001.phpt | 44 +++++++++++++++------- 4 files changed, 81 insertions(+), 37 deletions(-) (limited to 'ext/reflection') diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index f4d27b580b..c3c29d880b 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -3814,7 +3814,7 @@ ZEND_METHOD(reflection_class, getStaticProperties) ZEND_METHOD(reflection_class, getStaticPropertyValue) { reflection_object *intern; - zend_class_entry *ce; + zend_class_entry *ce, *old_scope; zend_string *name; zval *prop, *def_value = NULL; @@ -3827,7 +3827,12 @@ ZEND_METHOD(reflection_class, getStaticPropertyValue) if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) { return; } + + old_scope = EG(fake_scope); + EG(fake_scope) = ce; prop = zend_std_get_static_property(ce, name, BP_VAR_IS); + EG(fake_scope) = old_scope; + if (!prop) { if (def_value) { ZVAL_COPY(return_value, def_value); @@ -3847,7 +3852,7 @@ ZEND_METHOD(reflection_class, getStaticPropertyValue) ZEND_METHOD(reflection_class, setStaticPropertyValue) { reflection_object *intern; - zend_class_entry *ce; + zend_class_entry *ce, *old_scope; zend_property_info *prop_info; zend_string *name; zval *variable_ptr, *value; @@ -3861,7 +3866,10 @@ ZEND_METHOD(reflection_class, setStaticPropertyValue) if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) { return; } - variable_ptr = zend_std_get_static_property_with_info(ce, name, BP_VAR_W, &prop_info); + old_scope = EG(fake_scope); + EG(fake_scope) = ce; + variable_ptr = zend_std_get_static_property_with_info(ce, name, BP_VAR_W, &prop_info); + EG(fake_scope) = old_scope; if (!variable_ptr) { zend_clear_exception(); zend_throw_exception_ex(reflection_exception_ptr, 0, diff --git a/ext/reflection/tests/006.phpt b/ext/reflection/tests/006.phpt index ab22f5c5c9..0e33e0a6a1 100644 --- a/ext/reflection/tests/006.phpt +++ b/ext/reflection/tests/006.phpt @@ -88,16 +88,28 @@ TestDerived::testing(); string(3) "pub" string(3) "pub" string(7) "updated" -EXCEPTION -EXCEPTION +string(3) "pro" +string(3) "pro" +string(7) "updated" +string(3) "pri" +string(3) "pri" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" +string(7) "updated" string(7) "updated" string(7) "updated" string(7) "updated" -EXCEPTION -EXCEPTION string(7) "updated" string(7) "updated" string(7) "updated" -EXCEPTION -EXCEPTION ===DONE=== diff --git a/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt b/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt index 365ec89ff1..c63ee330d4 100644 --- a/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt +++ b/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt @@ -19,41 +19,47 @@ class B extends A { echo "Retrieving static values from A:\n"; $rcA = new ReflectionClass('A'); -var_dump($rcA->getStaticPropertyValue("privateOverridden", "default value")); -var_dump($rcA->getStaticPropertyValue("\0A\0privateOverridden")); -var_dump($rcA->getStaticPropertyValue("protectedOverridden", "default value")); -var_dump($rcA->getStaticPropertyValue("\0*\0protectedOverridden")); +var_dump($rcA->getStaticPropertyValue("privateDoesNotExist", "default value")); +var_dump($rcA->getStaticPropertyValue("privateOverridden")); +var_dump($rcA->getStaticPropertyValue("protectedDoesNotExist", "default value")); +var_dump($rcA->getStaticPropertyValue("protectedOverridden")); var_dump($rcA->getStaticPropertyValue("publicOverridden")); echo "\nRetrieving static values from B:\n"; $rcB = new ReflectionClass('B'); -var_dump($rcB->getStaticPropertyValue("\0A\0privateOverridden")); -var_dump($rcB->getStaticPropertyValue("\0B\0privateOverridden")); -var_dump($rcB->getStaticPropertyValue("\0*\0protectedOverridden")); +var_dump($rcB->getStaticPropertyValue("privateOverridden")); +var_dump($rcB->getStaticPropertyValue("protectedOverridden")); var_dump($rcB->getStaticPropertyValue("publicOverridden")); echo "\nRetrieving non-existent values from A with no default value:\n"; try { - var_dump($rcA->getStaticPropertyValue("protectedOverridden")); + var_dump($rcA->getStaticPropertyValue("protectedDoesNotExist")); echo "you should not see this"; } catch (Exception $e) { echo $e->getMessage() . "\n"; } try { - var_dump($rcA->getStaticPropertyValue("privateOverridden")); + var_dump($rcA->getStaticPropertyValue("privateDoesNotExist")); echo "you should not see this"; } catch (Exception $e) { echo $e->getMessage() . "\n"; } ?> ---EXPECTF-- +--EXPECT-- Retrieving static values from A: string(13) "default value" +string(16) "original private" +string(13) "default value" +string(18) "original protected" +string(15) "original public" + +Retrieving static values from B: +string(15) "changed private" +string(17) "changed protected" +string(14) "changed public" -Fatal error: Uncaught ReflectionException: Class A does not have a property named in %s:%d -Stack trace: -#0 %s(%d): ReflectionClass->getStaticPropertyValue('\x00A\x00privateOverr...') -#1 {main} - thrown in %s on line %d +Retrieving non-existent values from A with no default value: +Class A does not have a property named protectedDoesNotExist +Class A does not have a property named privateDoesNotExist diff --git a/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt index bfefce369e..41a6482f66 100644 --- a/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt +++ b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt @@ -19,41 +19,59 @@ class B extends A { echo "Set static values in A:\n"; $rcA = new ReflectionClass('A'); -$rcA->setStaticPropertyValue("\0A\0privateOverridden", "new value 1"); -$rcA->setStaticPropertyValue("\0*\0protectedOverridden", "new value 2"); +$rcA->setStaticPropertyValue("privateOverridden", "new value 1"); +$rcA->setStaticPropertyValue("protectedOverridden", "new value 2"); $rcA->setStaticPropertyValue("publicOverridden", "new value 3"); print_r($rcA->getStaticProperties()); echo "\nSet static values in B:\n"; $rcB = new ReflectionClass('B'); -$rcB->setStaticPropertyValue("\0A\0privateOverridden", "new value 4"); -$rcB->setStaticPropertyValue("\0B\0privateOverridden", "new value 5"); -$rcB->setStaticPropertyValue("\0*\0protectedOverridden", "new value 6"); +$rcB->setStaticPropertyValue("privateOverridden", "new value 4"); +$rcB->setStaticPropertyValue("privateOverridden", "new value 5"); +$rcB->setStaticPropertyValue("protectedOverridden", "new value 6"); $rcB->setStaticPropertyValue("publicOverridden", "new value 7"); print_r($rcA->getStaticProperties()); print_r($rcB->getStaticProperties()); echo "\nSet non-existent values from A with no default value:\n"; try { - var_dump($rcA->setStaticPropertyValue("protectedOverridden", "new value 8")); + var_dump($rcA->setStaticPropertyValue("protectedDoesNotExist", "new value 8")); echo "you should not see this"; } catch (Exception $e) { echo $e->getMessage() . "\n"; } try { - var_dump($rcA->setStaticPropertyValue("privateOverridden", "new value 9")); + var_dump($rcA->setStaticPropertyValue("privateDoesNotExist", "new value 9")); echo "you should not see this"; } catch (Exception $e) { echo $e->getMessage() . "\n"; } ?> ---EXPECTF-- +--EXPECT-- Set static values in A: +Array +( + [privateOverridden] => new value 1 + [protectedOverridden] => new value 2 + [publicOverridden] => new value 3 +) -Fatal error: Uncaught ReflectionException: Class A does not have a property named in %s:%d -Stack trace: -#0 %s(%d): ReflectionClass->setStaticPropertyValue('\x00A\x00privateOverr...', 'new value 1') -#1 {main} - thrown in %s on line %d +Set static values in B: +Array +( + [privateOverridden] => new value 1 + [protectedOverridden] => new value 2 + [publicOverridden] => new value 3 +) +Array +( + [privateOverridden] => new value 5 + [protectedOverridden] => new value 6 + [publicOverridden] => new value 7 +) + +Set non-existent values from A with no default value: +Class A does not have a property named protectedDoesNotExist +Class A does not have a property named privateDoesNotExist -- cgit v1.2.1