php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81041 Phpstan does not finish on Windows when opcache is enabled
Submitted: 2021-05-14 21:19 UTC Modified: 2021-12-29 23:34 UTC
From: mvorisek at mvorisek dot cz Assigned:
Status: Open Package: opcache
PHP Version: 7.4.19 OS: *
Private report: No CVE-ID: None
 [2021-05-14 21:19 UTC] mvorisek at mvorisek dot cz
Description:
------------
see https://github.com/mvorisek/phpstan-src/compare/00ff86b2eab4f8e67170394ca105ad65ba4b1104...13fb7e5f85cc7f053655d5e6529767da8b98bd26

Phpstan does not finish when opcache is enabled on Windows. I belive this is a bug in PHP, as opcache should not affect script execution and also because this bug is present on Windows OS only (NOT on Ubuntu).

Test script:
---------------
Github Actions workflow to reproduce on https://github.com/phpstan/phpstan-src repo.

on:
  push:

jobs:
  build:
    runs-on: "${{ matrix.runs-on }}"
    strategy:
      fail-fast: false
      matrix:
        runs-on:
          - "ubuntu-latest"
          - "windows-latest"
        php-version:
          - "7.4"
          - "8.0"
        ts:
          - "ts"
          - "nts"
        exclude:
          - runs-on: "ubuntu-latest"
            ts: ts
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "${{ matrix.php-version }}"
          extensions: intl
        env:
          phpts: "${{ matrix.ts }}"

      - name: "Install phpstan deps"
        env:
          COMPOSER_ROOT_VERSION: "0.12.x-dev"
        run: |
          composer install

      - name: "Clone & install test repo"
        run: |
          cd repro
          git clone https://github.com/atk4/ui.git && cd ui
          composer install

      - name: "Run PHPStan"
        run: |
          cd repro/ui
          php --version
          php ../../bin/phpstan clear-result-cache
          php -d memory_limit=2G ../../bin/phpstan analyse --ansi --debug --verbose

      - name: "Run PHPStan /w opcache enabled for CLI"
        run: |
          cd repro/ui
          php --version
          php ../../bin/phpstan clear-result-cache
          php -d memory_limit=2G -d opcache.enable=1 -d opcache.enable_cli=1 ../../bin/phpstan analyse --ansi --debug --verbose

Expected result:
----------------
phpstan finish on Windows (like it does on Ubuntu)

Actual result:
--------------
error during class fetch

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-05-14 21:44 UTC] daverandom@php.net
-Status: Open +Status: Feedback
 [2021-05-14 21:44 UTC] daverandom@php.net
Unfortunately this issue cannot currently be regarded as a PHP bug with the information presented. While it may be a fault in the engine that causes the problem, the PHP development team cannot debug applications as it is a long way outside their scope.

If you undertake further diagnostics which indicate a specific problem with PHP, please open a new bug report.
 [2021-05-14 22:16 UTC] mvorisek at mvorisek dot cz
I understand your feedback, but can you please ping some core developer of opcache?

In CLI, opcache is always cold on start, so the script should never notice opcache enabled, is this correct, or does opcache have some side effects?
 [2021-05-15 03:55 UTC] fjfjd at fjdjf dot fjf
opcache has a ton of optimization stages and so does far more than caching
 [2021-05-17 08:12 UTC] cmb@php.net
> In CLI, opcache is always cold on start, […]

On Windows, different CLI processes share a single OPcache
instance when running in parallel.  Use opcache.cache_id[1] to
enforce different caches.

[1] <https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.cache-id>
 [2021-05-17 08:46 UTC] m at m dot cz
> Use opcache.cache_id[1] to enforce different caches.

In CI, reproduced with no parallel processes, see https://github.com/mvorisek/phpstan-src/runs/2587303770
 [2021-05-17 14:03 UTC] nikic@php.net
To be clear, when you say "does not finish" you are talking about this fatal error, not about an infinite loop?

PHP Fatal error:  During class fetch: Uncaught PHPStan\Broker\ClassAutoloadingException: Class Atk4\Core\ReadableCaptionTrait not found. in D:\a\phpstan-src\phpstan-src\src\Reflection\Runtime\RuntimeReflectionProvider.php:186
Stack trace:
#0 [internal function]: PHPStan\Reflection\Runtime\RuntimeReflectionProvider->PHPStan\Reflection\Runtime\{closure}()
#1 D:\a\phpstan-src\phpstan-src\repro\ui\vendor\atk4\data\src\Field.php(17): spl_autoload_call()
#2 D:\a\phpstan-src\phpstan-src\vendor\composer\ClassLoader.php(478): include('D:\\a\\phpstan-sr...')
#3 D:\a\phpstan-src\phpstan-src\vendor\composer\ClassLoader.php(346): Composer\Autoload\includeFile()
#4 [internal function]: Composer\Autoload\ClassLoader->loadClass()
#5 [internal function]: spl_autoload_call()
#6 D:\a\phpstan-src\phpstan-src\src\Reflection\Runtime\RuntimeReflectionProvider.php(191): class_exists()
#7 D:\a\phpstan-src\phpstan-src\src\Reflection\ReflectionProvider\ClassBlacklistReflectionProvider.php(49): PHPStan\Reflection\Runtime\RuntimeReflectionProvider->hasCla in D:\a\phpstan-src\phpstan-src\repro\ui\vendor\atk4\data\src\Field.php on line 17
Fatal error: During class fetch: Uncaught PHPStan\Broker\ClassAutoloadingException: Class Atk4\Core\ReadableCaptionTrait not found. in D:\a\phpstan-src\phpstan-src\src\Reflection\Runtime\RuntimeReflectionProvider.php:186
Stack trace:
#0 [internal function]: PHPStan\Reflection\Runtime\RuntimeReflectionProvider->PHPStan\Reflection\Runtime\{closure}()
#1 D:\a\phpstan-src\phpstan-src\repro\ui\vendor\atk4\data\src\Field.php(17): spl_autoload_call()
#2 D:\a\phpstan-src\phpstan-src\vendor\composer\ClassLoader.php(478): include('D:\\a\\phpstan-sr...')
#3 D:\a\phpstan-src\phpstan-src\vendor\composer\ClassLoader.php(346): Composer\Autoload\includeFile()
#4 [internal function]: Composer\Autoload\ClassLoader->loadClass()
#5 [internal function]: spl_autoload_call()
#6 D:\a\phpstan-src\phpstan-src\src\Reflection\Runtime\RuntimeReflectionProvider.php(191): class_exists()
#7 D:\a\phpstan-src\phpstan-src\src\Reflection\ReflectionProvider\ClassBlacklistReflectionProvider.php(49): PHPStan\Reflection\Runtime\RuntimeReflectionProvider->hasCla in D:\a\phpstan-src\phpstan-src\repro\ui\vendor\atk4\data\src\Field.php on line 17
 [2021-05-17 14:08 UTC] m at m dot cz
About "different script result when run with opcache".

Issue can be reproduced consistently on different PC, PHP version/TS.
 [2021-05-17 22:12 UTC] cmb@php.net
-Status: Feedback +Status: Open -Assigned To: +Assigned To: cmb
 [2021-05-17 22:12 UTC] cmb@php.net
I shall have a closer look at this.
 [2021-05-18 13:42 UTC] m at m dot cz
@cmb I collected more than 100 GBs of xdebug trace logs and isolated the issue. The logs started to be different (after I removed randomness from time() and simillar func calls) on line 210 362 792.

Here are relevant short logs:
https://github.com/mvorisek/phpstan-src/commit/f9e1b786f6a210fd8573fd8d5caf1b9cd4815e45

They differ on line 121, with opcache disabled "include" calls spl_autoload_call, with opcache disabled, "include" returns true.
 [2021-05-18 21:43 UTC] cmb@php.net
-Status: Assigned +Status: Verified
 [2021-05-18 21:43 UTC] cmb@php.net
I'm able reliably reproduce the issue (with SHM or file cache),
and it is definitely a Windows only thing (on Linux, there are no
problems even with file cache only[1]).  Debugging this on Windows
is a bit hard, due to missing helpers (like .gdbinit), but I hope
to make some real progress tomorrow.

[1] <https://github.com/cmb69/phpstan-src/runs/2611756608>
 [2021-05-25 10:11 UTC] m at m dot cz
@cmb Did you get anywhere?
 [2021-05-27 17:13 UTC] cmb@php.net
On Windows with OPcache enabled, by the time
Atk4\Core\ReadableCaptionTrait is to be autoloaded,
PHPStan\Reflection\BetterReflection\SourceLocator\FileReadTrapStreamWrapper
is registered as file wrapper, so an empty file is compiled, and
the trait is not found.  That happens just for that single file;
all the rest is good.  I'm not sure that there is actually a bug
in php-src.
 [2021-05-27 20:05 UTC] m at m dot cz
Where else the bug should be? See the generated xdebug trace logs - I generated them in absolutely same enviromenment without any random/time functions used inside. One with opcache enabled, one with opcached disabled. And they differs.
 [2021-06-01 12:01 UTC] cmb@php.net
-Status: Verified +Status: Open -Operating System: Windows +Operating System: *
 [2021-06-01 12:01 UTC] cmb@php.net
Further findings: this is not particularly related to Windows;
you get the same failure on Ubuntu as well, with SHM cache[1]
and with file_cache_only[2].  However, the script runs fine as
soon as Xdebug is loaded, even on Windows[3].

Interestingly, running with file_cache_only and Xdebug (3.0.4)
loaded, there are no repro/ui/vendor/atk4/core files are generated
in the file cache.  That explains why the script is running fine
with Xdebug, although I have no idea why the files are not cached.
That might be an Xdebug issue.

[1] <https://github.com/cmb69/phpstan-src/actions/runs/895876662>
[2] <https://github.com/cmb69/phpstan-src/actions/runs/895872108>
[3] <https://github.com/cmb69/phpstan-src/actions/runs/895881729>
 [2021-06-08 15:10 UTC] cmb@php.net
-Status: Assigned +Status: Open -Assigned To: cmb +Assigned To:
 [2021-06-08 15:10 UTC] cmb@php.net
Unassigning myself – maybe someone else will have closer look.
 [2021-06-09 10:17 UTC] m at m dot cz
So there is some opcache issue with file_cache_only.

On Windows, I collected the trace logs using xDebug 2.9.x, see https://github.com/mvorisek/phpstan-src/commit/2f14329c69e457b494bab868b6d2c8247e283dc4#diff-3aea6cf619d0b900724dd43ee0706fcd5e1dfc6af9e6a455a98c8540c20bac2bR13 config, and the the issue was present even with xdebug. Please be aware, that it produces a trace log with size around 100 GB and it takes about 2 hours to complete.
 [2021-06-25 18:44 UTC] m at m dot cz
Can someone look at it? This may be a serious issue for every Windows platform as the problematic configuration is default and a lot of projects are CI tested against linux only.
 [2021-06-25 19:06 UTC] wfegeg dot wfwg at fff dot com
maybe php should do the same as bind and simply stop native windows support no longer needed these days - so much wasted time and code smell to workaround a operating system with no justification used as server

20 years ago virtualization and containers didn't exist but these days come on
 [2021-12-29 23:26 UTC] cmb@php.net
From the PHPStan 1.3.0 release announcement[1]:

| PHPStan now works when OPCache is enabled!
|   Thanks to this commit: phpstan/phpstan-src@e30f446

Might be worth to give it try with PHPStan 1.3.0.

| […] simply stop native windows support no longer needed these
| days […]

Feel free to pursue the RFC process[2].

[1] <https://github.com/phpstan/phpstan/releases/tag/1.3.0>
[2] <https://wiki.php.net/rfc/howto>
 [2021-12-29 23:34 UTC] cmb@php.net
> […] and a lot of projects are CI tested against linux only.

If they are supposed to be compatible with Windows, that would be
sad.  It shouldn't be hard to run unit tests on Windows, and even
tests requiring a Webserver should be viable.
 [2022-04-28 22:47 UTC] lars at moelleken dot org
I see the same problem with Ubuntu.

Here is the content of an empty/broken opcache file. (I expected more content in the file)

> cat /var/tmp/php7.4/opcache/377076abe2ab6ee0c4975c2061101f72/home/comain/vdmg/App/scripts/githooks/StandardVdmg/PHPStanHelper/MeerxErrorFormatter.php.bin
OPCACHE377076abe2ab6ee0c4975c2061101f72���ib4kX���@P`�?k�p@������������ib�@X�~jkbF�[��#�Y/home/comain/vdmg/App/scripts/githooks/StandardVdmg/PHPStanHelper/MeerxErrorFormatter.phpA����>F�[��#�Y/home/comain/vdmg/App/scripts/githooks/StandardVdmg/PHPStanHelper/MeerxErrorFormatter.php


----------------------
- System-Info
----------------------

> cat /etc/issue
Ubuntu 18.04.6 LTS

> php -v
PHP 7.4.29 (cli) (built: Apr 21 2022 10:16:17) ( NTS )

> cat /etc/php/7.4/cli/conf.d/50-opcache.ini
```
[opcache]
; Determines if Zend OPCache is enabled
opcache.enable=1

; Determines if Zend OPCache is enabled for the CLI version of PHP
opcache.enable_cli=1

; The OPcache shared memory storage size.
opcache.memory_consumption=1024

; The amount of memory for interned strings in Mbytes.
opcache.interned_strings_buffer=64

; The maximum number of keys (scripts) in the OPcache hash table.
; Only numbers between 200 and 100000 are allowed.
opcache.max_accelerated_files=100000

; The maximum percentage of "wasted" memory until a restart is scheduled.
;opcache.max_wasted_percentage=5

; When this directive is enabled, the OPcache appends the current working
; directory to the script key, thus eliminating possible collisions between
; files with the same name (basename). Disabling the directive improves
; performance, but may break existing applications.
opcache.use_cwd=1

; When disabled, you must reset the OPcache manually or restart the
; webserver for changes to the filesystem to take effect.
opcache.validate_timestamps=1

; How often (in seconds) to check file timestamps for changes to the shared
; memory storage allocation. ("1" means validate once per second, but only
; once per request. "0" means always validate)
opcache.revalidate_freq=0 ; For php-cli always validate php files

; File based OPCache (persistent opcode cache)
opcache.file_cache=/var/tmp/php7.4/opcache
opcache.file_cache_only=1 ; For php-cli use file-cache only
opcache.file_cache_consistency_checks=1
```
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 30 14:01:28 2024 UTC