Description
Just expanding on the description a little, in the following conditions:
- PHP8.5 is used (8.4 at least is not affected)
opcache.enable & opcache.enable_cli are enabled (This may not require enable_cli with other SAPIs, but my issue was on the CLI / this is where I have narrowed down the issue)
- A trait exists which has a
__toString method
- A class uses the above trait without declaring it implements
Stringable (the base class)
- A sub-class in a different file extends the base class (regardless of if implements
Stringable or not)
With the above conditions, then if you have:
- A process that runs for at least the time for the second/third steps)
- A process runs that loads the base class into opcache's shared memory
- A process runs that loads the file the sub-class is in is ran
The process in step 3 will crash with an exit code of -1073741819 (0xC0000005 - STATUS_ACCESS_VIOLATION).
The above process will also cause the crash if the long running process loads the base class into opcache's shared memory - the important points are that when step 3 happens there is a process that was running when the base class was loaded - it isn't relevant if it is the process that did the loading or not.
Full code for replicating:
Main file
<?php
$mode = $argv[1] ?? "";
if($mode === "hold"){
\sleep(30);
echo "hold ok\n";
exit(0);
}
trait TestTrait{
public function __toString() : string{
return "testString";
}
}
class TestBaseClass{
use TestTrait;
}
switch($mode){
case "base":
echo "base ok\n";
exit(0);
case "sub":
require __DIR__ . "/subclass.php";
echo "sub ok\n";
exit(0);
}
subclass.php:
<?php
class TestSubclass extends TestBaseClass{}
Commands to run (terminal one):
php -n -d opcache.enable=1 -d opcache.enable_cli=1 test.php hold
Commands to run (terminal two):
php -n -d opcache.enable=1 -d opcache.enable_cli=1 test.php base
echo %errorlevel%
php -n -d opcache.enable=1 -d opcache.enable_cli=1 test.php sub
echo %errorlevel%
Resulted in this output (terminal one):
Resulted in this output (terminal two):
But I expected this output instead (terminal one):
But I expected this output instead (terminal two):
PHP Version
PHP 8.4.6 (cli) (built: Apr 9 2025 09:45:15) (ZTS Visual C++ 2022 x64)
Copyright (c) The PHP Group
Zend Engine v4.4.6, Copyright (c) Zend Technologies
Operating System
Windows 11 x64
Description
Just expanding on the description a little, in the following conditions:
opcache.enable&opcache.enable_cliare enabled (This may not requireenable_cliwith other SAPIs, but my issue was on the CLI / this is where I have narrowed down the issue)__toStringmethodStringable(the base class)Stringableor not)With the above conditions, then if you have:
The process in step 3 will crash with an exit code of
-1073741819(0xC0000005- STATUS_ACCESS_VIOLATION).The above process will also cause the crash if the long running process loads the base class into opcache's shared memory - the important points are that when step 3 happens there is a process that was running when the base class was loaded - it isn't relevant if it is the process that did the loading or not.
Full code for replicating:
Main file
subclass.php:Commands to run (terminal one):
Commands to run (terminal two):
Resulted in this output (terminal one):
Resulted in this output (terminal two):
But I expected this output instead (terminal one):
But I expected this output instead (terminal two):
PHP Version
Operating System
Windows 11 x64