Bug #78921 [Ver->Csd]: When Reflection triggers class load, property visibility is incorrect
Edit report at https://bugs.php.net/bug.php?id=78921&edit=1
ID: 78921
Updated by: nikic@php.net
Reported by: theilig at box dot com
Summary: When Reflection triggers class load, property
visibility is incorrect
-Status: Verified
+Status: Closed
Type: Bug
Package: Reflection related
Operating System: centos7 OSX 18.7.0
PHP Version: 7.3.12
Block user comment: N
Private report: N
New Comment:
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=621598eaa8063a9e76447e07f6f3c30a8baca1e0
Log: Fixed bug #78921
Previous Comments:
------------------------------------------------------------------------
[2019-12-13 15:30:07] nikic@php.net
Single file:
<?php
spl_autoload_register(function($className) {
if ($className == 'PrivateStatic') {
class PrivateStatic
{
const SOME_CONST = 13;
private static $privateStaticVarArray = ['a', 'b', 'c'];
private static $otherStatic;
public static function init()
{
self::$otherStatic = self::$privateStaticVarArray;
}
}
PrivateStatic::init();
}
});
class OtherClass
{
const MY_CONST = PrivateStatic::SOME_CONST;
public static $prop = 'my property';
}
//class_exists('PrivateStatic');
$reflectionClass = new ReflectionClass('OtherClass');
$reflectionProperty = $reflectionClass->getProperty('prop');
$reflectionProperty->setAccessible(true);
$value = $reflectionProperty->getValue();
//$value = OtherClass::$prop;
echo "Value is $value\n";
------------------------------------------------------------------------
[2019-12-07 09:28:46] cmb@php.net
Introduced with commit db7ead0[1]. Inserting a var_dump($self)
in PrivateStatic::init() prints NULL.
[1] <http://git.php.net/?p=php-src.git;a=commit;h=db7ead0768076da486a9c98264061113233deb7f>
------------------------------------------------------------------------
[2019-12-07 06:57:56] theilig at box dot com
Description:
------------
If a class tries to use reflection to read a property of a second class, and that second class has a
property or a const that is initialized by a const reference to a third class, The scope for
visibility of properties is incorrect, The third class will not be able to access it's own
private static properties, but instead will have access to private static properties of a different
class! See the example code for more info.
OtherClass::$test isn't as private as it thinks!
Fatal error: Uncaught Error: Cannot access private property PrivateStatic::$privateStaticVarArray in
/Users/theilig/code/PhpBug/PrivateStatic.php on line 9
Error: Cannot access private property PrivateStatic::$privateStaticVarArray in
/Users/theilig/code/PhpBug/PrivateStatic.php on line 9
Call Stack:
0.0004 395896 1. {main}() /Users/theilig/code/PhpBug/ThirdClass.php:0
0.0010 398848 2. ReflectionProperty->getValue()
/Users/theilig/code/PhpBug/ThirdClass.php:9
0.0010 398968 3. spl_autoload_call() /Users/theilig/code/PhpBug/ThirdClass.php:9
0.0010 399008 4. {closure:/Users/theilig/code/PhpBug/ThirdClass.php:2-4}()
/Users/theilig/code/PhpBug/ThirdClass.php:9
0.0011 402480 5. include('/Users/theilig/code/PhpBug/PrivateStatic.php')
/Users/theilig/code/PhpBug/ThirdClass.php:3
0.0011 402480 6. PrivateStatic::init() /Users/theilig/code/PhpBug/PrivateStatic.php:12
You can see from the stack that the current function is PrivateStatic::init() which should be able
to access private static variables in the PrivateStatic class, but instead was able to read
OtherClass::$test which is private.
The code works correctly if either
1) The third class (PrivateStatic in the example) is forcefully loaded before the reflection call
"class_exists('PrivateStatic');
or
2) The field in the second class is public, and is referenced directly rather than via Reflection.
What I've seen via xdebug is that in php 7.1.29
$reflectionClass = new ReflectionClass('OtherClass');
will trigger the loading of PrivateStatic (and everything works correctly)
However in php 7.3.12
$reflectionClass = new ReflectionClass('OtherClass');
will only load OtherClass, and PrivateStatic isn't loaded until
$value = $reflectionProperty->getValue();
When the getValue call triggers the loading of PrivateStatic (and the running of the top level call
to PrivateStatic::init() ) then it appears to be picking up the scope of OtherClass
Test script:
---------------
https://github.com/theilig/PhpBug
% php ThirdClass.php
Expected result:
----------------
Expected result is:
PHP Fatal error: Uncaught Error: Cannot access private property OtherClass::$test in
/Users/theilig/code/PhpBug/PrivateStatic.php:9
Actual result:
--------------
OtherClass::$testisn't as private as it thinks!
PHP Fatal error: Uncaught Error: Cannot access private property
PrivateStatic::$privateStaticVarArray in /Users/theilig/code/PhpBug/PrivateStatic.php:10
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78921&edit=1
Thread (4 messages)