Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FileReadTrapStreamWrapper::stream_eof is not implemented! since 0.12.84 #4881

Closed
adrienfr opened this issue Apr 20, 2021 · 35 comments · Fixed by phpstan/phpstan-src#501
Closed

Comments

@adrienfr
Copy link

adrienfr commented Apr 20, 2021

Bug report

Since upgrading phpstan/phpstan (0.12.83 => 0.12.84), I encounter this error on CircleCI :

#!/bin/bash -eo pipefail
php bin/phpstan analyse --no-interaction --no-progress
Note: Using configuration file /home/circleci/project/symfony/phpstan.neon.dist.
PHP Warning: include(): PHPStan\Reflection\BetterReflection\SourceLocator\FileReadTrapStreamWrapper::stream_eof is not implemented! Assuming EOF in phar:///home/circleci/project/symfony/vendor/phpstan/phpstan/phpstan.phar/vendor/composer/ClassLoader.php on line 478
Warning: include(): PHPStan\Reflection\BetterReflection\SourceLocator\FileReadTrapStreamWrapper::stream_eof is not implemented! Assuming EOF in phar:///home/circleci/project/symfony/vendor/phpstan/phpstan/phpstan.phar/vendor/composer/ClassLoader.php on line 478
zend_mm_heap corrupted

Exited with code exit status 1
CircleCI received exit code 1

Code snippet that reproduces the problem

Update phpstan to 0.12.84 and run php bin/phpstan analyse --no-interaction --no-progress with a custom config file :

includes:
    - vendor/phpstan/phpstan-symfony/extension.neon
    - vendor/phpstan/phpstan-symfony/rules.neon
parameters:
    parallel:
        maximumNumberOfProcesses: 1
    level: 0
    paths:
        - src
        - tests
    excludes_analyse:
        - tests/DataFixtures
    tipsOfTheDay: false
    symfony:
        container_xml_path: '%rootDir%/../../../var/cache/test/App_KernelTestDebugContainer.xml'
    ignoreErrors:
        -
            message: '#Unsafe usage of new static\(\)\.#'
            paths:
                - [...]
        -
            message: '#Service "[^"]+" is private\.#'
            paths:
                - [...]

Expected output

#!/bin/bash -eo pipefail
php bin/phpstan analyse --no-interaction --no-progress
Note: Using configuration file /home/circleci/project/symfony/phpstan.neon.dist.

[OK] No errors

CircleCI received exit code 0

Could this be related to phpstan/phpstan-src#491 ? Ping @rrazor

@mergeable
Copy link

mergeable bot commented Apr 20, 2021

This bug report is missing a link to reproduction on phpstan.org.

It will most likely be closed after manual review.

@ondrejmirtes
Copy link
Member

Yeah, please @rrazor, could you look into this? Thanks!

@rrazor
Copy link

rrazor commented Apr 20, 2021 via email

@rrazor
Copy link

rrazor commented Apr 20, 2021

@adrienfr I have not been able to reproduce this issue with the code provided on my own. If I provide a clone of the phpstan repo with a modified .phar would you be willing to test it out in your environment, please? I suspect it's either related to loading very large files or it is an issue only seen on specific architectures.

@adrienfr
Copy link
Author

@rrazor thank you! Yes I can test with a custom cloned repo

@ondrejmirtes
Copy link
Member

Ideally I'd love a reproduction submitted similar to this one: 2bef7e4#diff-6d8749c4fe00b757c1bc1c376a99f31d1bd38b422d44f5b6aa2d6a6c5e975cba

@ondrejmirtes
Copy link
Member

Maybe some piece of code calls feof() and it executes the missing method? https://www.php.net/manual/en/streamwrapper.stream-eof.php

@rrazor
Copy link

rrazor commented Apr 20, 2021

@ondrejmirtes That's my thought. I've been using this php-src test stub as a guide for a minimal stream wrapper, and you can see there are some methods I've not implemented – I'm planning to implement those.

Ideally I'd like to repro this somehow using include or require, but I may resort to just dropping some feof() calls into the custom autoloader.

@ondrejmirtes
Copy link
Member

but I may resort to just dropping some feof() calls into the custom autoloader.

Yep, that might surface the bug :) Thank you really much, looks like you really know your stuff :)

This might also be an opportunity at looking at the other un-implemented methods and trying to surface other, not yet reported bugs.

@rrazor
Copy link

rrazor commented Apr 20, 2021

OK @adrienfr, please take a look at my fork of the main PHPStan repository and test with the phpstan.phar you will find in the root directory there. Thank you for your help.

@alfredbez
Copy link

I ran into the same error, looks like this in our CI job:

 -- --------------------------------------------------------------------------- 
     Error                                                                      
 -- --------------------------------------------------------------------------- 
     Child process error (exit code 1): PHP Warning:  include():                
     PHPStan\Reflection\BetterReflection\SourceLocator\FileReadTrapStreamWrapp  
     er::stream_eof is not implemented! Assuming EOF in                         
     /builds/XXXXXX/xxxxxxxxxxx/current/vendor/squizlabs/php_codesniffer/autol  
     oad.php on line 169                                                        
     Warning: include():                                                        
     PHPStan\Reflection\BetterReflection\SourceLocator\FileReadTrapStreamWrapp  
     er::stream_eof is not implemented! Assuming EOF in                         
     /builds/XXXXXX/xxxxxxxxxxx/current/vendor/squizlabs/php_codesniffer/autol  
     oad.php on line 169                                                        
     zend_mm_heap corrupted 

I can try to run that with the phpstan.phar from @rrazor tomorrow.

@adrienfr
Copy link
Author

adrienfr commented Apr 20, 2021

OK @adrienfr, please take a look at my fork of the main PHPStan repository and test with the phpstan.phar you will find in the root directory there. Thank you for your help.

Here is the output with the .phar provided :

#!/bin/bash -eo pipefail
php phpstan.phar analyse --no-interaction --no-progress
Note: Using configuration file /home/circleci/project/symfony/phpstan.neon.dist.
zend_mm_heap corrupted

Exited with code exit status 1
CircleCI received exit code 1

Tell me if you need anything to help

@rrazor
Copy link

rrazor commented Apr 20, 2021

@alfredbez Thank you for the additional report, I know that custom autoloader from PHP CodeSniffer, so perhaps that will help me repro the issue.

@adrienfr and @alfredbez, can you share any details about the build environment that may help me – OS, PHP version, Docker / not-Docker, etc.? It's very disconcerting to see a zend_* heap error.

@ondrejmirtes If I can't track this down quickly it may be best to revert my PR and release a new version.

@ondrejmirtes
Copy link
Member

I've had multiple problems with the PHP_CodeSniffer autoloader in the past (unrelated to this issue), you might be better off by not using it and just have PHP_CodeSniffer directory scanned with scanDirectories.

@alfredbez
Copy link

I got the error in Gitlab CI with the docker-image spryker/php:7.3

@adrienfr
Copy link
Author

I'm ont CircleCI with image debian:buster (php 7.3).
I can provide my CircleCI config file @rrazor if you want (ideally not publicly)

@coordtechjetpulp
Copy link

Same here in Gitlab CI (php 7.2 cli)

@alfredbez
Copy link

I tested that on several docker images like so:

docker run -it --rm -v $(pwd):/app -w /app imagename vendor/bin/phpstan-copy.phar analyze --memory-limit=5G

Here are my results:
spryker/php:7.3
✔️ php:7.3.27-alpine
prooph/php:7.3-cli-opcache
✔️ prooph/php:7.4-cli-opcache


Looks like this is related to opcache, so I tried to create a few small images and test that again:
alfredbez-local/php-7.2-alpine-opcache
✔️ php:7.2-alpine
alfredbez-local/php-7.3-alpine-opcache
✔️ php:7.3-alpine
✔️ alfredbez-local/php-7.4-alpine-opcache
✔️ php:7.4-alpine

Here's how I build the images to test that:

# 7.2-alpine-opcache/Dockerfile
FROM php:7.2-alpine
RUN docker-php-ext-configure opcache --enable-opcache && docker-php-ext-install opcache
COPY config/opcache.ini $PHP_INI_DIR/conf.d/
docker build -t alfredbez-local/php-7.2-alpine-opcache . # run this in the folder where the Dockerfile is
# 7.3-alpine-opcache/Dockerfile
FROM php:7.3-alpine
RUN docker-php-ext-configure opcache --enable-opcache && docker-php-ext-install opcache
COPY config/opcache.ini $PHP_INI_DIR/conf.d/
docker build -t alfredbez-local/php-7.3-alpine-opcache .
# 7.4-alpine-opcache/Dockerfile
FROM php:7.4-alpine
RUN docker-php-ext-configure opcache --enable-opcache && docker-php-ext-install opcache
COPY config/opcache.ini $PHP_INI_DIR/conf.d/
docker build -t alfredbez-local/php-7.4-alpine-opcache .

The output of the phar provided by @rrazor looks like this:

$ docker run -it --rm -v $(pwd):/app -w /app alfredbez-local/php-7.3-alpine-opcache:latest vendor/bin/phpstan-copy.phar analyze --memory-limit=5G
Note: Using configuration file /app/phpstan.neon.
  329/3280 [▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░]  10%zend_mm_heap corrupted

@dktapps
Copy link
Contributor

dktapps commented Apr 21, 2021

If you can run this under gdb, set a breakpoint at zend_mm_panic() and get a backtrace when it hits. It might help to pinpoint the issue.

@rrazor
Copy link

rrazor commented Apr 21, 2021

Awesome work @alfredbez this helps me a ton!

@alfredbez
Copy link

I've created a small repository to reproduce the issue here: https://github.com/alfredbez/phpstan-0-12-84-error/

You can see the error also in the Github Action here: https://github.com/alfredbez/phpstan-0-12-84-error/runs/2401281264?check_suite_focus=true#step:5:8

@rrazor
Copy link

rrazor commented Apr 21, 2021

I'm seeing the weirdest behavior inside the spryker/php:7.3 container!

bash-5.0# cat src/bootstrap.php
<?php

throw new Exception('haha');
bash-5.0# php src/bootstrap.php
bash-5.0# md5sum src/bootstrap*
adbd880c5cc124084c78182f306fc37d  src/bootstrap.php
adbd880c5cc124084c78182f306fc37d  src/bootstrap2.php
adbd880c5cc124084c78182f306fc37d  src/bootstrap3.php
bash-5.0# php src/bootstrap2.php
PHP Fatal error:  Uncaught Exception: haha in /opt/work/e2e/autoloader-require/src/bootstrap2.php:3
Stack trace:
#0 {main}
  thrown in /opt/work/e2e/autoloader-require/src/bootstrap2.php on line 3

Yes, that's right, identical files, but PHP just silently loads the first one for me with no Exception... I'm putting this down to Docker filesystem mounting issues, but no wonder I have been having trouble reproducing the issue.

@rrazor
Copy link

rrazor commented Apr 21, 2021

Wow, opcache on 7.3 seems quite troublesome in CLI, but I found a way to repro in spryker/php:7.3:

bash-5.0# rm -rf /var/run/opcache/*
bash-5.0# php ../../phpstan analyse --debug tests/ClassATest.php
Note: Using configuration file /opt/work/e2e/autoloader-require/phpstan.neon.
Reset opcache
/opt/work/e2e/autoloader-require/tests/ClassATest.php
zend_mm_heap corrupted

@rrazor
Copy link

rrazor commented Apr 22, 2021

Sorry everyone for the delay getting this resolved. After taking many passes at making the wrapper work in harmony with pre-7.4 OpCache, I think the simplest solution is for bin/phpstan to ini_set('opcache.enabled', 'Off').

@ondrejmirtes is that an acceptable solution for you?

@ondrejmirtes
Copy link
Member

@rrazor I'm sorry, could you summarize your thought process here? Is there any PHP version-specific bug that we're working around? I thought we're reproducing the problem when the stream_eof method needs to be implemented in stream wrapper. Thanks!

I'm not a fan of turning off OPCache for everyone here because I was looking forward to taking advantage of PHP 8's JIT in the future.

@rrazor
Copy link

rrazor commented Apr 22, 2021

@ondrejmirtes It is a PHP version-specific issue with versions before 7.4 with OpCache enabled. I'm not sure based on the various stack traces and implementations I've tried if I'm running into an OpCache bug with 7.3.x and earlier or not, but it seems likely. It makes sense that you wouldn't want to disable OpCache.

Another workaround could be to only support discovery of autoloaded files that use require / require_once in their autoloaders on PHP 7.4+. It seems like so far only I have been affected by such an autoloader, whereas many more folks are affected by an issue that creates a segfault in PHP 7.3.x and earlier.

A third route would be to revert my entire previous PR rather than have PHP-version-specific conditionals inside the FileReadTrapStreamWrapper, which is also understandable. That would buy me time to try and work around the OpCache bugs while at the same time getting everyone's CI builds passing again.

@ondrejmirtes
Copy link
Member

So there are two separate issues here? One that causes PHP to crash, and another one that asks the stream wrapper to have the stream_eof implemented?

Another workaround could be to only support discovery of autoloaded files that use require / require_once in their autoloaders on PHP 7.4+.

Isn't this reversed? We have a problem with the new approach on PHP 7.3 and lower. So the solution would be to only have require supported on PHP 7.3 and both require/include supported on PHP 7.4+, right?

Pragmatically, I think we could disable the OPCache on 7.3 and lower. It'd still be enabled for the JIT on PHP 8. Feel free to send a PR for bin/phpstan.

@rrazor
Copy link

rrazor commented Apr 22, 2021

@ondrejmirtes Ah, sorry, to summarize:

  • There was a PHP warning emitted because stream_eof was not implemented; I implemented that and the warning went away
  • There is a zend_mm_heap corrupted panic in PHP versions 7.3 and earlier that surfaces when we attempt to allow require and require_once via the stream wrapper. Previously, the wrapper only supported autoloaders that used include or include_once.

The first issue was simple to resolve and the folks on this ticket have confirmed the PHP warnings went away with the .phar I published.

The second issue seems to be related to OpCache. The ways I've found that make the issue go away are either to disable OpCache for these PHP versions or to revert the previous work that supports require and require_once.

Sounds like you are OK with dropping OpCache for older PHP versions, which is great.

I'll submit a PR that fixes the stream_eof warning and solves the zend_mm_heap corrupted issue shortly.

@ondrejmirtes
Copy link
Member

Awesome! Would be nice to also have the stream_eof warning reproduced here in phpstan/phpstan in e2e directory similarly to how I reproduced the require issue for the previous release. Feel free to have a composer.json there that uses PHP_CodeSniffer somehow (if that's what leads to reproducing it).

@rrazor
Copy link

rrazor commented Apr 22, 2021

I tried and failed to find a way to reproduce the EOF warning with a simple test case. I think to do so you need to have an autoloader registered from within a PHAR, like when phpstan itself is a composer dependency, like in @alfredbez's test repository. I wasn't sure how to do this in e2e testing.

@staabm
Copy link
Contributor

staabm commented Apr 22, 2021

There is a zend_mm_heap corrupted panic in PHP versions 7.3 and earlier that surfaces when we attempt to allow require and require_once via the stream wrapper.

@rrazor since you have the steps at hand to repro the problem, would it be worth it to report the problem to php-src?

ondrejmirtes added a commit that referenced this issue Apr 22, 2021
@Kingdutch
Copy link

Not sure if more info is needed but we’re seeing this in the drupal-graphql repo as well (which also uses CodeSniffer): https://github.com/drupal-graphql/graphql/pull/1194/checks?check_run_id=2410749566

@ondrejmirtes
Copy link
Member

Fixed by phpstan/phpstan-src#501, thanks everyone!

ondrejmirtes added a commit that referenced this issue Apr 23, 2021
phpstan/phpstan-src@18340a3 Address #4881 by implementing a more complete fake stream wrapper phpstan/phpstan-src@ce5f316 Disable OpCache for PHP < 7.4.x, #4881
@adrienfr
Copy link
Author

Thank you @rrazor , @ondrejmirtes & @alfredbez!

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 25, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
8 participants