Browse Source
Merge branch 'PHP-5.5' into PHP-5.6
Merge branch 'PHP-5.5' into PHP-5.6
* PHP-5.5: Fixed bug #51800 proc_open on Windows hangs foreverpull/862/merge
5 changed files with 327 additions and 0 deletions
-
91ext/standard/tests/streams/proc_open_bug51800.phpt
-
75ext/standard/tests/streams/proc_open_bug51800_right.phpt
-
67ext/standard/tests/streams/proc_open_bug60120.phpt
-
66ext/standard/tests/streams/proc_open_bug64438.phpt
-
28main/streams/plain_wrapper.c
@ -0,0 +1,91 @@ |
|||
--TEST-- |
|||
Bug #51800 proc_open on Windows hangs forever |
|||
--SKIPIF-- |
|||
<?php |
|||
if (getenv("SKIP_SLOW_TESTS")) { |
|||
die("skip slow test"); |
|||
} |
|||
?> |
|||
--XFAIL-- |
|||
pipes have to be read/written simultaneously |
|||
--FILE-- |
|||
<?php |
|||
/* This is the wrong way to do it. The parent will block till it has read all the STDIN. |
|||
The smaller the pipe buffer is, the longer it will take. It might even pass at the end, |
|||
after taking inappropriately long. Pipes have to be read simultaneously in smaller chunks, |
|||
so then the pipe buffer is emptied more often and the child has chance to continue its |
|||
write. The behaviour might look some better if write/read in a separate thread, however |
|||
this is much more resource greedy and complexer to integrate into the user script. */ |
|||
|
|||
$callee = dirname(__FILE__) . "/process" . md5(uniqid()) . ".php"; |
|||
$php = PHP_BINARY; |
|||
$cmd = "$php $callee"; |
|||
|
|||
$status; |
|||
$stdout = ""; |
|||
$stderr = ""; |
|||
$pipes = array(); |
|||
|
|||
$descriptors = array( |
|||
0 => array("pipe", "rb"), // stdin |
|||
1 => array("pipe", "wb"), // stdout |
|||
2 => array("pipe", "wb") // stderr |
|||
); |
|||
|
|||
/* create the proc file */ |
|||
$r = file_put_contents($callee, '<?php |
|||
|
|||
$how_much = 10000; |
|||
|
|||
$data0 = str_repeat("a", $how_much); |
|||
$data1 = str_repeat("b", $how_much); |
|||
fwrite(STDOUT, $data0); |
|||
fwrite(STDERR, $data1); |
|||
|
|||
exit(0); |
|||
'); |
|||
|
|||
if (!$r) { |
|||
die("couldn't create helper script '$callee'"); |
|||
} |
|||
|
|||
$process = proc_open($cmd, $descriptors, $pipes); |
|||
|
|||
if (is_resource($process)) |
|||
{ |
|||
fclose($pipes[0]); |
|||
|
|||
while (!feof($pipes[1])) |
|||
$stdout .= fread($pipes[1], 1024); |
|||
fclose($pipes[1]); |
|||
|
|||
while (!feof($pipes[2])) |
|||
$stderr .= fread($pipes[2], 1024); |
|||
fclose($pipes[2]); |
|||
|
|||
$status = proc_close($process); |
|||
} |
|||
|
|||
var_dump(array( |
|||
"status" => $status, |
|||
"stdout" => $stdout, |
|||
"stderr" => $stderr, |
|||
), strlen($stdout), strlen($stderr)); |
|||
|
|||
unlink($callee); |
|||
|
|||
?> |
|||
===DONE=== |
|||
--EXPECTF-- |
|||
array(3) { |
|||
["status"]=> |
|||
int(0) |
|||
["stdout"]=> |
|||
string(10000) "a%s" |
|||
["stderr"]=> |
|||
string(10000) "b%s" |
|||
} |
|||
int(10000) |
|||
int(10000) |
|||
===DONE=== |
|||
|
|||
@ -0,0 +1,75 @@ |
|||
--TEST-- |
|||
Bug #51800 proc_open on Windows hangs forever, the right way to do it |
|||
--FILE-- |
|||
<?php |
|||
$callee = dirname(__FILE__) . "/process" . md5(uniqid()) . ".php"; |
|||
$php = PHP_BINARY; |
|||
$cmd = "$php $callee"; |
|||
|
|||
$status; |
|||
$stdout = ""; |
|||
$stderr = ""; |
|||
$pipes = array(); |
|||
|
|||
$descriptors = array( |
|||
0 => array("pipe", "rb"), // stdin |
|||
1 => array("pipe", "wb"), // stdout |
|||
2 => array("pipe", "wb") // stderr |
|||
); |
|||
|
|||
/* create the proc file */ |
|||
$r = file_put_contents($callee, '<?php |
|||
|
|||
$how_much = 10000; |
|||
|
|||
$data0 = str_repeat("a", $how_much); |
|||
$data1 = str_repeat("b", $how_much); |
|||
fwrite(STDOUT, $data0); |
|||
fwrite(STDERR, $data1); |
|||
|
|||
exit(0); |
|||
'); |
|||
|
|||
if (!$r) { |
|||
die("couldn't create helper script '$callee'"); |
|||
} |
|||
|
|||
$process = proc_open($cmd, $descriptors, $pipes); |
|||
|
|||
if (is_resource($process)) |
|||
{ |
|||
fclose($pipes[0]); |
|||
|
|||
while (!feof($pipes[1]) || !feof($pipes[2])) { |
|||
$stdout .= fread($pipes[1], 1024); |
|||
$stderr .= fread($pipes[2], 1024); |
|||
} |
|||
fclose($pipes[1]); |
|||
fclose($pipes[2]); |
|||
|
|||
$status = proc_close($process); |
|||
} |
|||
|
|||
var_dump(array( |
|||
"status" => $status, |
|||
"stdout" => $stdout, |
|||
"stderr" => $stderr, |
|||
), strlen($stdout), strlen($stderr)); |
|||
|
|||
unlink($callee); |
|||
|
|||
?> |
|||
===DONE=== |
|||
--EXPECTF-- |
|||
array(3) { |
|||
["status"]=> |
|||
int(0) |
|||
["stdout"]=> |
|||
string(10000) "a%s" |
|||
["stderr"]=> |
|||
string(10000) "b%s" |
|||
} |
|||
int(10000) |
|||
int(10000) |
|||
===DONE=== |
|||
|
|||
@ -0,0 +1,67 @@ |
|||
--TEST-- |
|||
Bug #60120 proc_open hangs with stdin/out with 2048+ bytes |
|||
--FILE-- |
|||
<?php |
|||
error_reporting(E_ALL); |
|||
|
|||
$cmd = PHP_BINARY . ' -n -r "fwrite(STDOUT, $in = file_get_contents(\'php://stdin\')); fwrite(STDERR, $in);"'; |
|||
$descriptors = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w')); |
|||
$stdin = str_repeat('*', 1024 * 16) . '!'; |
|||
$stdin = str_repeat('*', 2049 ); |
|||
|
|||
$options = array_merge(array('suppress_errors' => true, 'binary_pipes' => true, 'bypass_shell' => false)); |
|||
$process = proc_open($cmd, $descriptors, $pipes, getcwd(), array(), $options); |
|||
|
|||
foreach ($pipes as $pipe) { |
|||
stream_set_blocking($pipe, false); |
|||
} |
|||
$writePipes = array($pipes[0]); |
|||
$stdinLen = strlen($stdin); |
|||
$stdinOffset = 0; |
|||
|
|||
unset($pipes[0]); |
|||
|
|||
while ($pipes || $writePipes) { |
|||
$r = $pipes; |
|||
$w = $writePipes; |
|||
$e = null; |
|||
$n = stream_select($r, $w, $e, 60); |
|||
|
|||
if (false === $n) { |
|||
break; |
|||
} elseif ($n === 0) { |
|||
proc_terminate($process); |
|||
|
|||
} |
|||
if ($w) { |
|||
$written = fwrite($writePipes[0], (binary)substr($stdin, $stdinOffset), 8192); |
|||
if (false !== $written) { |
|||
$stdinOffset += $written; |
|||
} |
|||
if ($stdinOffset >= $stdinLen) { |
|||
fclose($writePipes[0]); |
|||
$writePipes = null; |
|||
} |
|||
} |
|||
|
|||
foreach ($r as $pipe) { |
|||
$type = array_search($pipe, $pipes); |
|||
$data = fread($pipe, 8192); |
|||
var_dump($data); |
|||
if (false === $data || feof($pipe)) { |
|||
fclose($pipe); |
|||
unset($pipes[$type]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
?> |
|||
===DONE=== |
|||
--EXPECTF-- |
|||
string(2049) "%s" |
|||
string(2049) "%s" |
|||
string(0) "" |
|||
string(0) "" |
|||
===DONE=== |
|||
|
|||
@ -0,0 +1,66 @@ |
|||
--TEST-- |
|||
Bug #64438 proc_open hangs with stdin/out with 4097+ bytes |
|||
--FILE-- |
|||
<?php |
|||
|
|||
error_reporting(E_ALL); |
|||
|
|||
$cmd = PHP_BINARY . ' -n -r "fwrite(STDOUT, $in = file_get_contents(\'php://stdin\')); fwrite(STDERR, $in);"'; |
|||
$descriptors = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w')); |
|||
$stdin = str_repeat('*', 4097); |
|||
|
|||
$options = array_merge(array('suppress_errors' => true, 'binary_pipes' => true, 'bypass_shell' => false)); |
|||
$process = proc_open($cmd, $descriptors, $pipes, getcwd(), array(), $options); |
|||
|
|||
foreach ($pipes as $pipe) { |
|||
stream_set_blocking($pipe, false); |
|||
} |
|||
$writePipes = array($pipes[0]); |
|||
$stdinLen = strlen($stdin); |
|||
$stdinOffset = 0; |
|||
|
|||
unset($pipes[0]); |
|||
|
|||
while ($pipes || $writePipes) { |
|||
$r = $pipes; |
|||
$w = $writePipes; |
|||
$e = null; |
|||
$n = stream_select($r, $w, $e, 60); |
|||
|
|||
if (false === $n) { |
|||
break; |
|||
} elseif ($n === 0) { |
|||
proc_terminate($process); |
|||
|
|||
} |
|||
if ($w) { |
|||
$written = fwrite($writePipes[0], (binary)substr($stdin, $stdinOffset), 8192); |
|||
if (false !== $written) { |
|||
$stdinOffset += $written; |
|||
} |
|||
if ($stdinOffset >= $stdinLen) { |
|||
fclose($writePipes[0]); |
|||
$writePipes = null; |
|||
} |
|||
} |
|||
|
|||
foreach ($r as $pipe) { |
|||
$type = array_search($pipe, $pipes); |
|||
$data = fread($pipe, 8192); |
|||
var_dump($data); |
|||
if (false === $data || feof($pipe)) { |
|||
fclose($pipe); |
|||
unset($pipes[$type]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
?> |
|||
===DONE=== |
|||
--EXPECTF-- |
|||
string(4097) "%s" |
|||
string(4097) "%s" |
|||
string(0) "" |
|||
string(0) "" |
|||
===DONE=== |
|||
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue