Bug #71341 [Fbk->Csd]: Engine can forget about classes in edge-cases with streams and opcache enabled
| From: | cmb@php.net | Date: | Mon, 12 Jul 2021 20:44:46 +0000 |
| Subject: | Bug #71341 [Fbk->Csd]: Engine can forget about classes in edge-cases with streams and opcache enabled | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-234990@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=71341&edit=1
ID: 71341
Updated by: cmb@php.net
Reported by: lisachenko dot it at gmail dot com
Summary: Engine can forget about classes in edge-cases with
streams and opcache enabled
-Status: Feedback
+Status: Closed
Type: Bug
Package: opcache
Operating System: MacOS
PHP Version: 7.0.2
Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
Thanks for checking!
Previous Comments:
------------------------------------------------------------------------
[2021-07-12 20:12:50] lisachenko dot it at gmail dot com
I have checked this issue for 7.4 and 8.0 - cannot reproduce anymore, all good, this bug can be
closed.
------------------------------------------------------------------------
[2021-07-08 11:37:39] cmb@php.net
Is this still an issue with any of the actively supported PHP
versions[1]?
[1] <https://www.php.net/supported-versions.php>
------------------------------------------------------------------------
[2016-01-11 18:59:49] lisachenko dot it at gmail dot com
Description:
------------
I'm playing with hidden PHP features and noticed one bug, when PHP forgets about all loaded
classes (get_declared_classes() will return empty array). This case is reproduced only with enabled
opcache module and some dark magic:
1. Register new stream filter class implementation (it performs an AST-analysis and transformation
for my case)
2. Unregister the standard stream wrapper handler for the 'file' protocol via
stream_wrapper_unregister('file') and then register a custom one handler (see https://github.com/goaop/ast-manipulator/blob/master/src/Hook/StreamWrapperHook.php).
stream_open() method implementation temporary restores original handler and opens a file with
enabled stream filter via 'php://filter/read=filter.id' mechanism. After that it enables
custom hook again.
3. Now include a class via "include" keyword to trigger stream wrapper and stream filter
processing.
If opcache is enabled then PHP tries to load DemoClass and then goes crazy starting to report about
missing classes that was previously loaded and crashing with fatal errors that class is not loaded
yet, even built-in, such as \Exception, \stdClass, etc.
So, this related to opcache + "file" stream wrapper + stream filter + include keyword
handling. For opcache it will be better not to cache such dirty cases or take an $openedPath from
StreamWrapper::stream_open() argument for checking the hash key:
public function stream_open($path, $mode, $options, &$openedPath)
If this openedPath argument is filled and is not empty, then opcache can take the compiled version
of opcodes from that key instead of original one $path.
Test script:
---------------
<?php
// composer require goaop/ast-manipulator:dev-master to clone project
// the put this content into the root and run in web
include __DIR__ . '/vendor/autoload.php';
\Go\AstManipulator\Engine::init();
\Go\AstManipulator\Hook\StreamWrapperHook::activateHook();
$class = new \Go\AstManipulator\DemoClass(); <== weird stuff here
$class->foo();
Expected result:
----------------
Hello, world!
Actual result:
--------------
Warning: stream_wrapper_register(): class 'Go\AstManipulator\Hook\StreamWrapperHook' is
undefined in ../ast-manipulator/src/Hook/StreamWrapperHook.php on line 39
Warning: stream_wrapper_register(): class 'Go\AstManipulator\Hook\StreamWrapperHook' is
undefined in ../ast-manipulator/src/Hook/StreamWrapperHook.php on line 39
Fatal error: Call to a member function parse() on a non-object in ../ast-manipulator/src/Engine.php
on line 97
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=71341&edit=1