diff --git a/src/future/exec/ExecFuture.php b/src/future/exec/ExecFuture.php --- a/src/future/exec/ExecFuture.php +++ b/src/future/exec/ExecFuture.php @@ -817,7 +817,18 @@ $max_stderr_read_bytes); } + $is_done = false; if (!$status['running']) { + // We may still have unread bytes on stdout or stderr, particularly if + // this future is being buffered and streamed. If we do, we don't want to + // consider the subprocess to have exited until we've read everything. + // See T9724 for context. + if (feof($stdout) && feof($stderr)) { + $is_done = true; + } + } + + if ($is_done) { if ($this->useWindowsFileStreams) { fclose($stdout); fclose($stderr); diff --git a/src/future/exec/__tests__/ExecFutureTestCase.php b/src/future/exec/__tests__/ExecFutureTestCase.php --- a/src/future/exec/__tests__/ExecFutureTestCase.php +++ b/src/future/exec/__tests__/ExecFutureTestCase.php @@ -150,6 +150,9 @@ // We expect to get the entire string back in the read. $this->assertEqual($str_len_4, $read); + + // Remove the limit so we can resolve the future. + $future->setReadBufferSize(null); $future->resolve(); }