squizlabs / PHP_CodeSniffer

PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.
BSD 3-Clause "New" or "Revised" License
10.67k stars 1.48k forks source link

RuntimeException: Undefined variable: childOutput in squizlabs/php_codesniffer/src/Runner.php on line 705 #2304

Closed yoeunes closed 5 years ago

yoeunes commented 5 years ago

Description

I get this exception when i run phpcs using a parallel value greater than 1

Fatal error: Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in /Users/yoeunes/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php on line 705 in /Users/yoeunes/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php:562
Stack trace:
#0 /Users/yoeunes/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php(705): PHP_CodeSniffer\Runner->handleErrors(8, 'Undefined varia...', '/Users/yoeunes/...', 705, Array)
#1 /Users/yoeunes/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php(502): PHP_CodeSniffer\Runner->processChildProcs(Array)
#2 /Users/yoeunes/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php(114): PHP_CodeSniffer\Runner->run()
#3 /Users/yoeunes/.composer/vendor/squizlabs/php_codesniffer/bin/phpcs(18): PHP_CodeSniffer\Runner->runPHPCS()
#4 {main}
  thrown in /Users/yoeunes/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php on line 562

this is my phpcs.xml file:

<?xml version="1.0"?>
<ruleset name="coding standard">
    <description>coding standard</description>

    <arg name="extensions" value="php"/>

    <arg name="parallel" value="2"/>

    <file>src</file>

    <rule ref="PSR2" />

</ruleset>
gsherwood commented 5 years ago

I can't replicate this (php 7.3, mac os), but it would mean that something pretty bad has gone wrong. If you are using a parallel value of 2, it means at least one of the two forks has exited but not written any data to the output file. I assume this means it died early, but I'm not sure why. It could be that the temp output file couldn't be written for some reason.

Without adding debug information into the runner, I'm not really sure how to figure out where it is dying. But there are some things to try:

If you can try those things and post your findings, maybe something might show up.

Alternatively, if you'd like to add some debug code, I'd start in src/Runner.php at about line 497 to see if it is getting to the place where the file is written. Something like this:

$output .= ";\n?".'>';
echo "ABOUT TO WRITE TO $childOutFilename\n";
file_put_contents($childOutFilename, $output);
echo "ABOUT TO EXIT\n";
exit($pid);
yoeunes commented 5 years ago

Thank you @gsherwood for your response.

This is the output with -v argument:

$ ./vendor/bin/phpcs -v
Registering sniffs in the Tamtam coding standard standard... DONE (42 sniffs registered)
Creating file list... DONE (1 files in queue)

I get the error in this line: https://github.com/squizlabs/PHP_CodeSniffer/blob/ab6caa0a7e23bbe48d8a12c5c7a3c2f1ab1dad9e/src/Runner.php#L702-L709

The existence of $childOutput variable was checked for another bloc above and not for line 705:

https://github.com/squizlabs/PHP_CodeSniffer/blob/ab6caa0a7e23bbe48d8a12c5c7a3c2f1ab1dad9e/src/Runner.php#L679-L685

adding and isset condition arround that bloc fixed my problem

adaoudi commented 5 years ago

I had the same issue :(

gsherwood commented 5 years ago

adding and isset condition arround that bloc fixed my problem

I figured it would, but I asked for more testing because it would be good to find out why your child processes are not outputting data. If they aren't producing output, it is quite likely that you are not seeing errors that are being generated.

This is why I asked if you could do some test runs over a single file, then 2 identical files. You need to be sure that the results you are getting are still valid, or else you are just hiding a very serious error.

alies-dev commented 5 years ago

I have the same error when a use --parallel value >1. PHP 7.3.0 (cli)

kevinfodness commented 5 years ago

@gsherwood You're right, this is more complicated. The child processes aren't outputting any data. It dies quietly on this line, and then continues the loop, therefore never reaching the code that outputs the file contents: https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Runner.php#L454

kevinfodness commented 5 years ago

More info: this function call successfully runs, but anything placed after this function call does not: https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Files/LocalFile.php#L74

Adding logging to the setContent function demonstrates that it is successfully completing the function call without an error getting caught, but nothing after that is doing anything.

Due to the absence of error/warning/notice output and the fact that the script seems to mysteriously die, this feels to me like a possible race condition, in which the thing that is causing the script to stop is the fatal itself.

Axent96 commented 5 years ago

I have the same problem with php 7.3. One Project ist okey and another have the problem. I can it reproduce only on mac and on alpine is fine.

esetnik commented 5 years ago

I have the same issue on mac using brew install php version 7.3.1:

❯ php -v
PHP 7.3.1 (cli) (built: Jan 10 2019 13:15:37) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.1, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.1, Copyright (c) 1999-2018, by Zend Technologies

Downgrading back to v7.1.23 works correctly

sebastiaanluca commented 5 years ago

Getting these too in PHPStorm with CodeSniffer enabled since updating to 7.3 (brew). Don't have the parallel option set in my config, but maybe PHPStorm sets it.

phpcs: PHP Fatal error: Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in …/vendor/squizlabs/php_codesniffer/src/Runner.php on line 712
icetee commented 5 years ago

Yep, crash in PHP 7.3.1 (cli) (built: Jan 10 2019 13:15:37) ( NTS ) (homebrew)

gsherwood commented 5 years ago

The only way I can get the error to happen is if the child processes run out of memory.

Is it possible that the fatal error is being suppressed for anyone, and that the child processes are actually dying due to memory limits?

GaryJones commented 5 years ago

PHP 7.3.1 and 7.3.2 PHPCS 3.4.0

My notes for what I tried in getting to the outcome below > * Run phpcs with the `-v` command line argument to see debug output and ensure it is at least checking files ```sh ➜ vipcs git:(fix/ruleset-test-improvements) ✗ vendor/bin/phpcs tests/RulesetTest.php -v Registering sniffs in the VIP Coding Standards standard... DONE (227 sniffs registered) Creating file list... DONE (1 files in queue) PHP Fatal error: Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in /path/to/vendor/squizlabs/php_codesniffer/src/Runner.php on line 712 in /path/to/vendor/squizlabs/php_codesniffer/src/Runner.php:569 ``` > * Run phpcs over a single file (still with parallel=2) to see if the temp file creation is working As above. > * Run phpcs over exactly 2 files, ideally with the same content Duplicated RulsetTest.php and the command. Output as above. As expected, commenting out the `parallel` arg, and it all works fine. > Alternatively, if you'd like to add some debug code As above (though with different line numbers due to the additional debug code). I added my own debugging within `processChildProcs()`. When I had `parallel` of 5, then I had 5 items in my `$childProcs`. Of those, the first file (`/private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childFKGge9`) did not exist (but commenting out the later `unlink`, and future runs showed the first child process output did exist), but the other 4 child process files did exist. They were empty. When I added a debug inside of the `file_exists($procData['out']) === true`, and ran it again, it suggested the file exists (and the `include` returned `int(1)`, but may have been empty, since none of the three isset variable checks returned as true. At a guess, this does seem to suggest that when `parallel` is set, the child process files are not being written. I did some more debugging earlier Runner::run(), at the `// Batching and forking.` point. When running with `parallel` 5, I each batch is looped through and a child process is created (`$pid !== 0`). Batch 0 and 1 had a child process created immediately. Batch 2, 3 and 4 took a detour through the `else` first (`// Move forward to the start of the batch.`). That suggests that one or two child processes are not going through the code logic that ends up writing to the file. In terms of that file writing process, there's some output buffering - I could get some echos working just before the `ob_start()`, but could not get anything inside the buffering to output (even by echoing `$debugOutput`), or any echo after it. It seems as though the logic just stops somewhere in or after that output buffering. The was my output - note the inconsistent position of ob_start - perhaps there's some sort of race condition going on?: ``` Batch: 0 Child process created. PID = 39705 Batch: 1 Child process created. PID = 39706 Batch: 2 ob_start about to be called Child process created. PID = 39707 Batch: 3 ob_start about to be called Child process created. PID = 39708 Batch: 4 ob_start about to be called Child process created. PID = 39709 Batch: 5 ob_start about to be called Child process created. PID = 39710 ob_start about to be called Batch: 6 Child process created. PID = 39711 Batch: 7 ob_start about to be called Child process created. PID = 39712 ob_start about to be called Batch: 8 Child process created. PID = 39713 Batch: 9 ob_start about to be called Child process created. PID = 39714 ob_start about to be called File /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childddCFiP exists.ob_start about to be called PHP Fatal error: Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in /Users/gary/code/vipcs/vendor/squizlabs/php_codesniffer/src/Runner.php on line 724 in /Users/gary/code/vipcs/vendor/squizlabs/php_codesniffer/src/Runner.php:578 ``` Either way, with no processing getting past that output buffering, no child process temp files are even getting to the `$childOutput` array assignment, let alone building the `$output` and eventually writing it to file. From the [docs](https://secure.php.net/manual/en/outcontrol.configuration.php) (my emphasis): > `output_buffering` boolean/integer > You can enable output buffering for all files by setting this directive to 'On'. If you wish to limit the size of the buffer to a certain size - you can use a maximum number of bytes instead of 'On', as a value for this directive (e.g., output_buffering=4096). **This directive is always Off in PHP-CLI.**

Outcome

Taking it in a different direction, I added an echo 'FINISHED LOOP after the loops had finished, right before the $this->processChildProcs($childProcs);, and some debugging inside the loop right before and after each file was supposedly written.

Here's my extra debug code (starting [here])(https://github.com/squizlabs/PHP_CodeSniffer/blob/a982ecd9b62742887817b176431b9a36d64ede72/src/Runner.php#L533):


                    $output .= ";\n?".'>';
echo 'About to write file ' . $childOutFilename . "\n";
                    file_put_contents($childOutFilename, $output);
//var_dump( file_get_contents( $childOutFilename ) );
                    exit($pid);
                }//end if
            }//end for

echo 'FINISHED LOOP' . "\n";

And my output:


Batch: 0
Child process created. PID = 40174

Batch: 1
Child process created. PID = 40175

Batch: 2
About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-child4FQCyE
Child process created. PID = 40176

Batch: 3
About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childedI8Ol
Child process created. PID = 40177

Batch: 4
About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childE3LXir
Child process created. PID = 40178

FINISHED LOOP
About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-child6DuKPE
About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childujhpCQ
File /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-child4FQCyE exists.

(That last "File ... exists" message is in processChildProcs().)

In this case, the FINISHED LOOP was appearing, before all of the the var_dump() was output - suggesting that some processing is hitting it, before all loops have actually finished (back to the race condition possibility). That in turns means the processChildProcs() call (where the reported undefined variable is), is being called before all child process temp files have been written.

With PHP 7.2, my output is:

Batch: 0
Child process created. PID = 46277
Batch: 1
Child process created. PID = 46278
Batch: 2
Child process created. PID = 46279
Batch: 3
Child process created. PID = 46280
Batch: 4
Child process created. PID = 46281
FINISHED LOOP
About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childr37H17
File /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childr37H17 exists.
.About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childRI5nsH
File /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childRI5nsH exists.
EAbout to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childjTwoSr
File /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childjTwoSr exists.
.About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childvQ8Fjk
File /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childvQ8Fjk exists.
.About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childe4qV6Z
File /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childe4qV6Z exists.
. 5 / 5 (100%)

Which again suggests the same regarding initial file-writing, but it is in a different order, but more importantly, each file exists before it is processed.

Both PHP 7.3 and 7.2 have been compiled with --enable-pcntl.

If I echo $res; near the top of processChildProcs(), for PHP 7.2, there are screens and screens of zeros, even for the first file. With 7.3, there are considerably fewer for the first one. Maybe a speed optimisation for PHP 7.3 has revealed a race condition? If there was a way to not have $this->processChildProcs($childProcs); called until all child processes had been created and their temp files written to, then I think this would resolve the issue.

gsherwood commented 5 years ago

In this case, the FINISHED LOOP was appearing, before all of the the var_dump() was output - suggesting that some processing is hitting it, before all loops have actually finished (back to the race condition possibility). That in turns means the processChildProcs() call (where the reported undefined variable is), is being called before all child process temp files have been written.

The way this is supposed to work means that FINISHED LOOP should almost always appear before any files are written. The call to processChildProcs() would normally happen before any of the child processes have completed their processing because they are normally checking a large number of files each. Not always, but often.

The processChildProcs() method uses pcntl_waitpid() with the WNOHANG flag to see if any of the child processes have completed. Once it finds one, it goes ahead and opens the file that the child process should have written. If the file doesn't exist, it doesn't try to open anything. If it does exist, it assumes there will be a var inside called $childOutput. It shouldn't matter when this loop starts as it is waiting for specific process IDs to be completed. If they are already done by the time the loop starts, they will be processed immediately. If not, the loop will wait.

Given that the error here is $childOutput does not exist, it means that the file_exists() call inside processChildProcs() passed, and so the pcntl_waitpid() call also found that the child process had ended. The file content itself was empty though. So this means that the child process did start correctly and was able to make a call to tempnam() to create the temp file (the one that is later empty) but pcntl_waitpid() tells the parent process that the child has completed before the file was written.

So either the child died before it could write to the file, or the pcntl_waitpid() function is saying that the child process has ended before it actually ended.

Debug code right before the exit($pid); line in the child would be good. If the processChildProcs() loop thinks the process has ended before the exit() call is made, something has gone wrong. The debug output you have commented out is probably the most important bit. Are you able to put that back in and see if you are able to retrieve the file contents before the process ends?

GaryJones commented 5 years ago

Thank you for that explanation. It would be useful for future readers to have some of that added to DocBlocks / inline comments, for those of us who aren't familiar with child processes in PHP.

Are you able to put that back in and see if you are able to retrieve the file contents before the process ends?

Yes. For brevity, I commented out the var_dump() and hadn't been including it by dumps here, but I thought that yes, the file was being written and I could retrieve the contents. However, I've just tried it again, and the results are different:

For PHP 7.2, all looks good:

PHP 7.2 output ```sh Batch: 0 Child process created. PID = 3574 Batch: 1 Child process created. PID = 3575 Batch: 2 Child process created. PID = 3576 Batch: 3 Child process created. PID = 3577 Batch: 4 Child process created. PID = 3578 About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childTt63fF Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childTt63fF string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" .About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childMqOLG4 Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childMqOLG4 string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" .About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childwA0158 Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childwA0158 string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" .About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childFU5kxL Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childFU5kxL string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" .About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childSgSQwZ Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childSgSQwZ string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" . 5 / 5 (100%) ```

For PHP 7.3, it doesn't get to the var_dump call:

PHP 7.3 output ```php Batch: 0 Child process created. PID = 12676 Batch: 1 Child process created. PID = 12677 Batch: 2 Child process created. PID = 12678 Batch: 3 Child process created. PID = 12679 Batch: 4 Child process created. PID = 12680 PHP Fatal error: Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in /Users/gary/code/vipcs/vendor/squizlabs/php_codesniffer/src/Runner.php on line 718 in /Users/gary/code/vipcs/vendor/squizlabs/php_codesniffer/src/Runner.php:575 ```

There's a debug line after ob_end_clean(); that is not getting called for PHP 7.3.

If I comment out the block of code from ob_start() down to ob_end_clean(), and add a $debugOutput = '';, then it seems to work:

PHP 7.3 with output buffering disabled ```sh Batch: 0 Child process created. PID = 29038 Batch: 1 Child process created. PID = 29039 Batch: 2 About to call ob_start(). About to call ob_start(). About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-child5eVgKr Child process created. PID = 29040 Batch: 3 About to call ob_start(). About to call ob_start(). Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-child5eVgKr About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-child4wstxf Child process created. PID = 29041 string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-child4wstxf Batch: 4 About to call ob_start(). About to call ob_start(). string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childLZlUc5 Child process created. PID = 29042 Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childLZlUc5 About to call ob_start(). About to call ob_start(). string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-child7cSNNY Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-child7cSNNY About to call ob_start(). About to call ob_start(). string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" About to write file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childkRG6dF Retrieving contents of file /private/var/folders/3_/nz1_2g_927sf2hp3k2xb3mr40000gn/T/phpcs-childkRG6dF string(165) " 0, 'totalErrors' => 0, 'totalWarnings' => 0, 'totalFixable' => 0, 'totalFixed' => 0, ); $debugOutput = ''; ?>" ..... 5 / 5 (100%) ```

I can't find any reference to what's intentionally changed regarding output buffering for PHP 7.3. I use brew install php for my version of PHP 7.3 (and 7.2), and php -i | grep ouput_ shows it has the same values as with PHP 7.2.


I commented out the ob_*() start, get and end lines, and it still didn't give file outputs, so it doesn't appear to be anything to do with OB itself, only something within that block.

I commented out the following, it worked:

$file = $todo->current();

if ($file->ignored === true) {
    continue;
}

...

$this->processFile($file);

If any of them was uncommented, it failed again (that latter two because $file was undefined).

I looked more into FileList::current() - if I returned early from this, it worked.

rdohms commented 5 years ago

If it helps I had the same issue in PHP 7.3.1, but it stopped when I upgraded to PHP 7.3.2.

rdohms commented 5 years ago

Actually that may be a false positive, it started happening again after the first run, so upon php upgrade the first run was ok, the second and all since then, not.

gagan0123 commented 5 years ago

Brought to this issue upon searching for the error message. Using OSX with Homebrew, PHPCS version 3.4.0 with PHP 7.3.2 Here's more info for debugging:

PHP Version output ``` $ php --version PHP 7.3.2 (cli) (built: Feb 5 2019 22:19:09) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.3.2, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.3.2, Copyright (c) 1999-2018, by Zend Technologies ```
PHPCS Version output ``` $ phpcs --version PHP_CodeSniffer version 3.4.0 (stable) by Squiz (http://www.squiz.net) ```
Error output ``` $ phpcs PHP Fatal error: Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php on line 2 in phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php:2 Stack trace: #0 phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php(2): PHP_CodeSniffer\Runner->handleErrors(8, 'Undefined varia...', 'phar:///usr/loc...', 2, Array) #1 phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php(2): PHP_CodeSniffer\Runner->processChildProcs(Array) #2 phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php(2): PHP_CodeSniffer\Runner->run() #3 /usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs(6): PHP_CodeSniffer\Runner->runPHPCS() #4 {main} thrown in phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php on line 2 Fatal error: Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php on line 2 in phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php:2 Stack trace: #0 phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php(2): PHP_CodeSniffer\Runner->handleErrors(8, 'Undefined varia...', 'phar:///usr/loc...', 2, Array) #1 phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php(2): PHP_CodeSniffer\Runner->processChildProcs(Array) #2 phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php(2): PHP_CodeSniffer\Runner->run() #3 /usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs(6): PHP_CodeSniffer\Runner->runPHPCS() #4 {main} thrown in phar:///usr/local/Cellar/php-code-sniffer/3.4.0/bin/phpcs/src/Runner.php on line 2 ```
gagan0123 commented 5 years ago

Just an update, after switching to php 7.2.15, error disappeared.

$ brew unlink php
$ brew link php@7.2 --force
ryancco commented 5 years ago

I am also running into this this issue running macOS Mojave (10.14.3)

❯ php --version
PHP 7.3.2 (cli) (built: Feb  5 2019 22:19:09) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.2, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.2, Copyright (c) 1999-2018, by Zend Technologies

❯ phpcs --version
PHP_CodeSniffer version 3.4.0 (stable) by Squiz (http://www.squiz.net)

❯ phpcs . 
PHP Fatal error:  Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php on line 712 in /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php:569
Stack trace:
#0 /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php(712): PHP_CodeSniffer\Runner->handleErrors(8, 'Undefined varia...', '/Users/ryan/.co...', 712, Array)
#1 /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php(509): PHP_CodeSniffer\Runner->processChildProcs(Array)
#2 /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php(114): PHP_CodeSniffer\Runner->run()
#3 /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/bin/phpcs(18): PHP_CodeSniffer\Runner->runPHPCS()
#4 {main}
  thrown in /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php on line 569

Fatal error: Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php on line 712 in /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php:569
Stack trace:
#0 /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php(712): PHP_CodeSniffer\Runner->handleErrors(8, 'Undefined varia...', '/Users/ryan/.co...', 712, Array)
#1 /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php(509): PHP_CodeSniffer\Runner->processChildProcs(Array)
#2 /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php(114): PHP_CodeSniffer\Runner->run()
#3 /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/bin/phpcs(18): PHP_CodeSniffer\Runner->runPHPCS()
#4 {main}
  thrown in /Users/ryan/.composer/vendor/squizlabs/php_codesniffer/src/Runner.php on line 569
derotune commented 5 years ago

Update on this?

gsherwood commented 5 years ago

Update on this?

I'm still unable to replicate this issue, even using the same OS and PHP versions as stated here. If anyone can provide a repo or container or anything to help replicate the problem, I'd be very grateful.

miguelci commented 5 years ago

had the same issue on a Mac with php 7.3.3. downgraded to php 7.2.16 and its working fine again.

voku commented 5 years ago

We had the same issue and for us it seems related to "symlinked" files and "parallel" execution?

PHP Fatal error:  Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined index:  in phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Files/FileList.php on line 2 in phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php:2
Stack trace:
#0 phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Files/FileList.php(2): PHP_CodeSniffer\Runner->handleErrors(8, 'Undefined index...', 'phar:///home/co...', 2, Array)
#1 phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php(2): PHP_CodeSniffer\Files\FileList->current()
#2 phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php(2): PHP_CodeSniffer\Runner->run()
#3 /home/USER/PROJECT/Framework/thirdparty/phpcs.phar(6): PHP_CodeSniffer\Runner->runPHPCS()
#4 {main}
  thrown in phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php on line 2
PHP Fatal error:  Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: Undefined variable: childOutput in phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php on line 2 in phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php:2
Stack trace:
#0 phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php(2): PHP_CodeSniffer\Runner->handleErrors(8, 'Undefined varia...', 'phar:///home/co...', 2, Array)
#1 phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php(2): PHP_CodeSniffer\Runner->processChildProcs(Array)
#2 phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php(2): PHP_CodeSniffer\Runner->run()
#3 /home/USER/PROJECT/Framework/thirdparty/phpcs.phar(6): PHP_CodeSniffer\Runner->runPHPCS()
#4 {main}
  thrown in phar:///home/USER/PROJECT/Framework/thirdparty/phpcs.phar/src/Runner.php on line 2
gsherwood commented 5 years ago

We had the same issue and for us it seems related to "symlinked" files and "parallel" execution?

I've just tried running over symlinked files with parallel execution of PHP 7.3 and still can't replicate any failures.

GaryJones commented 5 years ago

@gsherwood How did you install your PHP 7.3? I'm wondering if that could be a difference here.

voku commented 5 years ago

@gsherwood I saw the following changes on the server at the same day, where I saw this error the first time, maybe it's related to "symlink" + "parallel"? Or maybe it's a timing thing, because on that day the server was very busy?

<- /etc/sysctl.d/90-lxc-host.conf

gsherwood commented 5 years ago

@GaryJones I use phpbrew to run multiple PHP versions on mac OS.

Edit: also via a docker container running 7.3 - but same result.

gagan0123 commented 5 years ago

@gsherwood

Here's a sample repo on which you'll see the errors we've mentioned: https://github.com/WordPress/wordpress-develop

gsherwood commented 5 years ago

@gagan0123 Thanks for posting this repo, but I couldn't replicate any issues using php 7.3.

I cloned the repo, composer install, vendor/bin/phpcs and it ran 20 processes. It found A TOTAL OF 2467 ERRORS AND 964 WARNINGS WERE FOUND IN 480 FILES without generating any child process errors.

gagan0123 commented 5 years ago

@gsherwood I was earlier running PHPCS 3.4.0, today I upgraded to 3.4.1 but still the error persists Here's my terminal recording, can you point out what I did wrong? asciicast

gagan0123 commented 5 years ago

Update: We don't even need that repo to replicate this, nor any third party standards list, here's the simplest replication I could do, with a clean install of PHPCS and PHP7.3 using Homebrew:

asciicast

gsherwood commented 5 years ago

I've managed to replicate this with a new brew installed version of PHP 7.3.4. Comparing that to my known working versions of 7.3, I've found that this php.ini setting appears to be the problem:

; Enables or disables JIT compilation of patterns. This requires the PCRE
; library to be compiled with JIT support.
;pcre.jit=1

Note that it is commented out, but the default value is obviously to enable this. Disabling this fixes the problems for me, and reflects what my working 7.3 installs have already done by default:

; Enables or disables JIT compilation of patterns. This requires the PCRE
; library to be compiled with JIT support.
pcre.jit=0

I debugged PHPCS as far as I could to determine why the child processes were failing, but it looked like the process just died between function calls. But this is a regex extension and I did notice that leaving the EOL char of files empty did allow the script to continue longer, but die from other reasons.

I'll keep looking into this to see if there is a particular regex that the jit is breaking. If I can't find one, I'll see if I can disable or detect this ini setting during a PHPCS run, or just detect that the child process has died and fail the entire run (means you wont be able to use the parallel option with the jit enabled).

gsherwood commented 5 years ago

From the Generic standard, these are the sniffs that each cause errors when the jit is enabled:

Generic.PHP.Syntax
Generic.Commenting.Todo
Generic.WhiteSpace.DisallowTabIndent
Generic.PHP.DisallowAlternativePHPTags
Generic.WhiteSpace.DisallowSpaceIndent
Generic.Commenting.Fixme
gsherwood commented 5 years ago

I thought this was caused by complex regular expressions, but changing the TODO code to just be:

$matches = [];
preg_match('/(.*)/', 'foo', $matches);

Also causes the process to die. I'm not sure that I can actually fix this. I might need to disable the jit during PHPCS runs.

gsherwood commented 5 years ago

I ended up just disabling the pcre jit for PHPCS (c09a4e1a2f3f6fe4a628e72b5e61ad35b309ed02). I couldn't figure out why the processes were dying and why a simple regex would kill it.

I've also changed the process handling code so that PHPCS will die with a more specific error message rather than just an undefined var error.

If anyone is able to test this fix, I'd be very grateful. Or even just disabling the jit in your php.ini to confirm that is the cause for you as well.

GaryJones commented 5 years ago

I can confirm that turning off JIT for PHP 7.3, allows PHPCS to run with parallel > 1.

GaryJones commented 5 years ago

And the fix seems to work too:

Screenshot 2019-04-09 at 01 57 30

(That's with my php.ini set back to ;pcre.jit=1)

gsherwood commented 5 years ago

@GaryJones Thanks for testing that for me.

gagan0123 commented 5 years ago

It Works 😃

@gsherwood Thanks for being so patient with this bug and helping us out

🤔 Still wondering why it works with JIT enabled on PHP 7.2 but not on PHP 7.3

gagan0123 commented 5 years ago

Found this on PHP 7.3 Migration notes, worth looking into to resolve this without disabling JIT performance benefits

https://www.php.net/manual/en/migration73.other-changes.php#migration73.other-changes.pcre

So in PHP 7.3 they upgraded PCRE to PCRE2. This has caused issues in many other projects as well.

gsherwood commented 5 years ago

worth looking into to resolve this without disabling JIT performance benefits

That's what I was trying to do, but it appeared that simple calling preg_match was enough to silently segfault or something, no matter what regex or string I used. But only when running after forking, and even then it wasn't the first regex that PHPCS was using. So I'm a bit lost on this.

gsherwood commented 5 years ago

Thanks @GaryJones and @gagan0123 for testing. I'm going to close this so this change can be released in 3.4.2.

If anyone is continuing to have issues that this fix does not resolve, then it is likely to be a different problem and a new issue should be opened. If anyone has any idea how to get the parallel option working with the jit, please open an issue to discuss that as well.

Thanks to everyone who provided info to help track this down.

jrfnl commented 5 years ago

This may need to be investigated by PHP itself - has anyone checked if there are bugs reported against PHP 7.3 for PCRE2 vs the pcre.jit option ?

gagan0123 commented 5 years ago

@jrfnl Yes there are several projects that started reporting issues because of PCRE2 update, but most of them simply disabled pcre.jit for the time being, and haven't resolved the underlying issue.

@gsherwood Creating new issue for support of pcre.jit. Having it disabled is quite a performance hit, as it optimises the performance of same regular expressions running again and again which in PHPCS provides a performance boost.

jrfnl commented 5 years ago

@gagan0123 Thanks for checking.

If disabling pcre.jit solves the issue, I doubt the issue is a regex being incompatible with PCRE2 as in that case, the regex wouldn't (shouldn't) work on PHP 7.3 with pcre.jit turned off either.

This, to me, still sounds more like a problem with the PCRE2 implementation in PHP 7.3 itself and possibly support for pcre.jit not being fully implemented, not so much something which can be solved in userland code.

gagan0123 commented 5 years ago

@jrfnl You're right, its not compatibility with PCRE2 thats causing the issue. I profiled the command using xdebug and with some luck found the exact line causing the issue.

Currently child processes in PHPCS are failing at https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Util/Common.php#L143

But I doubt this line if of any concern, since child processes are quitting at any preg_match statement in a forked process with Segmentation Fault signal(SIGSEGV).

Its an issue localised to PHP 7.3.x running on MacOS. I've tested on Ubuntu 18.04 with PHP 7.3.3-1+ubuntu18.04.1+deb.sury.org+1 and it works perfectly fine.

So I don't think we should hamper the performance benefits of having pcre.jit enabled, for everyone.

Right now building docker image with PHP 7.3 on alpine, once its built, will test on that as well. https://travis-ci.com/gagan0123/wp-testing-docker/jobs/191527120

gagan0123 commented 5 years ago

Update: It even works with PHP 7.3.4 on Alpine as well.

jrfnl commented 5 years ago

@gagan0123 Oh wow! Well done with the debugging!

If it helps: I was never able to reproduce the issue on Windows, so can confirm, based on one user testing, that things work fine on Windows.

https://github.com/squizlabs/PHP_CodeSniffer/blob/master/src/Util/Common.php#L143

Just had a quick look at that regex, even though it may not be the actual issue. I know PCRE2 is stricter regarding syntax and the | should really be within parentheses, so I'd be interested to see if changing the line to the below would make a difference:

if (preg_match("/(?:\r\n?|\n)/", $contents, $matches) !== 1) {
gagan0123 commented 5 years ago

Thanks for confirming it works on Windows 😃

I tested with parentheses as well, but it didn't work either, thing is, on MacOS, any statement with preg_match within a forked child process results in segmentation fault, no matter what you put inside.

Learnt a lot while debugging this issue, thanks to @yoeunes for bringing this up 👍