Bug #65650 [Com]: Using proc_open with file handles fails on large buffers
| From: | bill at zeroedin dot com | Date: | Thu, 24 Jul 2014 15:04:23 +0000 |
| Subject: | Bug #65650 [Com]: Using proc_open with file handles fails on large buffers | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-186800@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=65650&edit=1
ID: 65650
Comment by: bill at zeroedin dot com
Reported by: imprec at gmail dot com
Summary: Using proc_open with file handles fails on large
buffers
Status: Open
Type: Bug
Package: Program Execution
Operating System: Irrelevant
PHP Version: 5.4.19
Block user comment: N
Private report: N
New Comment:
Your example code doesn't work for me.
In both PHP 5.4 and PHP 5.5, it spams "
Warning: proc_get_status(): 7 is not a valid process resource in C:\wamp\www\surveyor\65650_e.php on
line 27
Warning: proc_close(): 7 is not a valid process resource in C:\wamp\www\surveyor\65650_e.php on line
29" to the console indefinitely.
I rewrote the example code to behave properly and I am unable to verify this bug.
New test script:
----------------
<?php
error_reporting(E_ALL);
$cmd = sprintf('SET XDEBUG_CONFIG=&"C:\wamp\bin\php\php5.5.12\php.exe" -r
%s', escapeshellarg('fwrite(STDOUT, $in = file_get_contents(\'php://stdin\'));
fwrite(STDERR, $in);'));
$stdout = tmpfile();
$stderr = tmpfile();
$descriptors = array(
array('pipe', 'r'),
$stdout,
$stderr,
);
$handles = array(
$stdout, $stderr
);
$datastdin = str_repeat('*!', 1024*1024*20);
$options = array_merge(array('suppress_errors' => true, 'binary_pipes' =>
true, 'bypass_shell' => false));
$process = proc_open($cmd, $descriptors, $pipes, getcwd(), array(), $options);
$status = proc_get_status($process);
fwrite($pipes[0], $datastdin);
fclose($pipes[0]);
unset($pipes[0]);
$read = array();
$start = microtime(true);
$timeout = 10;
while ($status['running']) {
if((microtime(true) - $start) > $timeout) {
echo "timed out.";
break;
}
usleep(150000);
$status = proc_get_status($process);
}
proc_close($process);
rewind($stdout);
rewind($stderr);
$read['stdout'] = stream_get_contents($stdout);
$read['stderr'] = stream_get_contents($stderr);
fclose($stdout);
fclose($stderr);
$failed = false;
foreach ($read as $r) {
if(!assert($r === $datastdin)) {
$failed = true;
}
}
if($failed) {
echo "It's a bug!";
} else {
echo "It's not a bug!";
}
Expected result:
-----------------
It's not a bug!
Actual result:
--------------
It's not a bug!
Tested on Windows 8.1 using php versions 5.5.12-nts and 5.4.31-nts.
Previous Comments:
------------------------------------------------------------------------
[2013-09-10 15:10:07] imprec at gmail dot com
Update email
------------------------------------------------------------------------
[2013-09-10 15:04:25] imprec at gmail dot com
Description:
------------
When using proc_open with file handles instead of pipes (required on Windows,
because of bug https://bugs.php.net/bug.php?id=51800), when
reading large outputs,
the result might not retrieve what's expected.
The problem has been mentioned when compiling large sass files to stdout on
windows. The output may sometimes be different than the actual output you can get
running the command in console.
The provided script fails 3 times on 5 on windows environment. Nearly everytime on
OSX.
Test script:
---------------
<?php
error_reporting(E_ALL);
$cmd = sprintf('php -r %s', escapeshellarg('fwrite(STDOUT, $in =
file_get_contents(\'php://stdin\')); fwrite(STDERR, $in);'));
$stdout = tmpfile();
$stderr = tmpfile();
$descriptors = array(
array('pipe', 'r'),
$stdout,
$stderr,
);
$handles = array(
$stdout, $stderr
);
$datastdin = str_repeat('*!', 8192*128);
$options = array_merge(array('suppress_errors' => true, 'binary_pipes' =>
true, 'bypass_shell' => false));
$process = proc_open($cmd, $descriptors, $pipes, getcwd(), array(), $options);
fwrite($pipes[0], $datastdin);
fclose($pipes[0]);
unset($pipes[0]);
$read = array();
while ($handles) {
$status = proc_get_status($process);
if (!$status['running']) {
proc_close($process);
}
$h = $handles;
foreach ($h as $offset => $handle) {
fseek($handle, isset($read[$offset]) ? strlen($read[$offset]) : 0);
if (!isset($read[$offset])) {
$read[$offset] = '';
}
$read[$offset] .= fread($handle, 8192);
if (false === $status['running'] && feof($handle)) {
fclose($handle);
unset($handles[$offset]);
}
}
}
foreach ($read as $r) {
assert($r === $datastdin);
}
Expected result:
----------------
No errors, assertion is good.
Actual result:
--------------
PHP Warning: assert(): Assertion failed in C:\symfony\src\Symfony\Component\Pro
cess\bug.php on line 47
PHP Warning: assert(): Assertion failed in C:\symfony\src\Symfony\Component\Pro
cess\bug.php on line 47
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=65650&edit=1