- fixed bug #60120, proc_open's streams may hang with stdin/out/err when the data...
authorPierre Joye <pajoye@php.net>
Mon, 24 Oct 2011 12:39:55 +0000 (12:39 +0000)
committerPierre Joye <pajoye@php.net>
Mon, 24 Oct 2011 12:39:55 +0000 (12:39 +0000)
NEWS
ext/standard/proc_open.c
ext/standard/tests/file/bug60120.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index be39e98f7cc631ca2d8f2d82a33df932b28c435c..f6f960fb6cabc819ca61c3bcaf7f2dd75141402e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ PHP                                                                        NEWS
 ?? ??? 2011, PHP 5.3.9
 
 - Core:
+  . Fixed bug #60120 (proc_open's streams may hang with stdin/out/err when 
+    the data exceeds or is equal to 2048 bytes). (Pierre, Pascal Borreli)
   . Fixed bug #60019 (Function time_nanosleep() is undefined on OS X). (Ilia)
   . Fixed bug #55798 (serialize followed by unserialize with numeric object
     prop. gives integer prop). (Gustavo)
index bc9f7b1ba21245cba6fd46ba1a71326a3c0a2b6f..d91699e4edba823d9469d609b52e361aa5f570fc 100644 (file)
@@ -451,7 +451,7 @@ PHP_FUNCTION(proc_get_status)
 
 /* {{{ handy definitions for portability/readability */
 #ifdef PHP_WIN32
-# define pipe(pair)            (CreatePipe(&pair[0], &pair[1], &security, 2048L) ? 0 : -1)
+# define pipe(pair)            (CreatePipe(&pair[0], &pair[1], &security, 0) ? 0 : -1)
 
 # define COMSPEC_NT    "cmd.exe"
 
diff --git a/ext/standard/tests/file/bug60120.phpt b/ext/standard/tests/file/bug60120.phpt
new file mode 100644 (file)
index 0000000..8915bb8
--- /dev/null
@@ -0,0 +1,74 @@
+--TEST--\r
+Bug #60120 (proc_open hangs when data in stdin/out/err is getting larger or equal to 2048)\r
+--SKIPIF--\r
+<?php\r
+if (substr(PHP_OS, 0, 3) != 'WIN') {\r
+    die('skip only for Windows');\r
+}\r
+$php = getenv('TEST_PHP_EXECUTABLE');\r
+if (!$php) {\r
+       die("No php executable defined\n");\r
+}\r
+?>\r
+--FILE--\r
+<?php\r
+\r
+error_reporting(E_ALL);\r
+\r
+$php = getenv('TEST_PHP_EXECUTABLE');\r
+if (!$php) {\r
+       die("No php executable defined\n");\r
+}\r
+$cmd = 'php -r "fwrite(STDOUT, $in = file_get_contents(\'php://stdin\')); fwrite(STDERR, $in);"';\r
+$descriptors = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w'));\r
+$stdin = str_repeat('*', 1024 * 16) . '!';\r
+$stdin = str_repeat('*', 2049 );\r
+\r
+$options = array_merge(array('suppress_errors' => true, 'binary_pipes' => true, 'bypass_shell' => false));\r
+$process = proc_open($cmd, $descriptors, $pipes, getcwd(), array(), $options);\r
+\r
+foreach ($pipes as $pipe) {\r
+    stream_set_blocking($pipe, false);\r
+}\r
+$writePipes = array($pipes[0]);\r
+$stdinLen = strlen($stdin);\r
+$stdinOffset = 0;\r
+\r
+unset($pipes[0]);\r
+\r
+while ($pipes || $writePipes) {\r
+    $r = $pipes;\r
+    $w = $writePipes;\r
+    $e = null;\r
+    $n = stream_select($r, $w, $e, 60);\r
+\r
+    if (false === $n) {\r
+        break;\r
+    } elseif ($n === 0) {\r
+        proc_terminate($process);\r
+\r
+    }\r
+    if ($w) {\r
+        $written = fwrite($writePipes[0], (binary)substr($stdin, $stdinOffset), 8192);\r
+        if (false !== $written) {\r
+            $stdinOffset += $written;\r
+        }\r
+        if ($stdinOffset >= $stdinLen) {\r
+            fclose($writePipes[0]);\r
+            $writePipes = null;\r
+        }\r
+    }\r
+\r
+    foreach ($r as $pipe) {\r
+        $type = array_search($pipe, $pipes);\r
+        $data = fread($pipe, 8192);\r
+        if (false === $data || feof($pipe)) {\r
+            fclose($pipe);\r
+            unset($pipes[$type]);\r
+        }\r
+    }\r
+}\r
+echo "OK.";\r
+?>\r
+--EXPECT--\r
+OK.\r