sebastianbergmann/phpunit — pull request #1340 by sun (2014-07-22 15:17:39+00:00)
Title: Process isolation blocks infinitely upon fatal error in child process

| PHPUnit | Platform
| --- | ---
| 4.1.3 | Windows 7 64-bit

When using `--process-isolation`, `@runTestsInSeparateProcess`, or `@runInSeparateProcess` and the child process terminates with a PHP Fatal Error, the parent process blocks infinitely on Windows.

The fix is to read `stderr` before `stdout`.

cf. https://bugs.php.net/bug.php?id=51800:
> If called as shown below, the script will hang in the loop that reads the STDOUT pipe. The same would happen if you would read the STDERR pipe before. If you lower the amount of data in process.php the script will run to the end. In my tests everything below ~2000 bytes was ok, above this value the script hang.
>
> If you change the script below to not include the STDERR descriptor or if you change the STDERR descriptor to a file output everything will work fine. Also if you close the STDERR pipe before reading from STDOUT it will work. There seems to be some deadlock.

---
`stderr` contains the fatal error, `stdout` is empty. I had to debug this phantom for the past two days…:

After `stdin` is written/processed and closed, `stream_get_meta_data($pipes[1])` reports that `stdout` still appears to be present:
```
$ phpunit -v --debug --process-isolation ...
PHPUnit 4.1.3 by Sebastian Bergmann.

Starting test '...'.
array(7) {
'stream_type' =>
string(5) "STDIO"
'mode' =>
string(1) "r"
'unread_bytes' =>
int(0)
'seekable' =>
bool(false)
'timed_out' =>
bool(false)
'blocked' =>
bool(true)
'eof' =>
bool(false)
}
```
But as soon as `$stdout = stream_get_contents($pipes[1])` is called, the script hangs.

Changing the order in which `$stdout` and `$stderr` are read suddenly fixes the problem, and `stream_get_meta_data()` reports the same info for both pipes.

---
All of the usual resolutions for this common problem did not work in this case, and I'm not able to explain why. However, I'd like to make clear that I did try all of the below:

1. [Opening stderr in append mode instead of write mode](http://php.net/manual/en/function.proc-open.php#97012): Normally, that is almost always the solution. However, for some reason, this caused the parent process to not receive any output on stderr at all, and so a test passed despite a fatal error.
1. [Setting stderr to non-blocking](http://php.net/manual/en/function.proc-open.php#81317): As mentioned in this [user comment](http://php.net/manual/en/function.stream-set-blocking.php#110997), that's not supported by `proc_open()` on Windows.
* https://bugs.php.net/bug.php?id=51800
* https://bugs.php.net/bug.php?id=34972
* https://bugs.php.net/bug.php?id=47918
1. …

**D'oh.** Somehow I didn't notice the first PHP bug link. [#51800](https://bugs.php.net/bug.php?id=51800) fully cuts it. Nothing further to add to that.

Since the bug is still unresolved, I'd recommend to move forward with this PR as-is and just simply change the order in which stderr and stdout are read.