php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71341 Engine can forget about classes in edge-cases with streams and opcache enabled
Submitted: 2016-01-11 18:59 UTC Modified: 2021-07-12 20:44 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: lisachenko dot it at gmail dot com Assigned: cmb (profile)
Status: Closed Package: opcache
PHP Version: 7.0.2 OS: MacOS
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: lisachenko dot it at gmail dot com
New email:
PHP Version: OS:

 

 [2016-01-11 18:59 UTC] 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

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-07-08 11:37 UTC] cmb@php.net
-Status: Open +Status: Feedback -Assigned To: +Assigned To: cmb
 [2021-07-08 11:37 UTC] 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>
 [2021-07-12 20:12 UTC] 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-12 20:44 UTC] cmb@php.net
-Status: Feedback +Status: Closed
 [2021-07-12 20:44 UTC] cmb@php.net
Thanks for checking!
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 02 20:01:32 2024 UTC