php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #51800 proc_open on Windows hangs forever
Submitted: 2010-05-12 17:31 UTC Modified: 2013-05-08 06:33 UTC
Votes:30
Avg. Score:4.7 ± 0.7
Reproduced:27 of 28 (96.4%)
Same Version:11 (40.7%)
Same OS:22 (81.5%)
From: ph dot wolfer at googlemail dot com Assigned: ab (profile)
Status: Closed Package: Streams related
PHP Version: * OS: Windows
Private report: No CVE-ID: None
 [2010-05-12 17:31 UTC] ph dot wolfer at googlemail dot com
Description:
------------
On Windows, if you use proc_open to open another process and if you use a pipe for STDERR, the script will hang when trying to read from STDOUT or STDERR if the opened process outputs a lot of data.

See the example below. The called script process.php is a simple script which writes some data to STDOUT and STDERR:

$data = str_repeat("a", 10000); 
fwrite(STDOUT, $data);
fwrite(STDERR, $data);
exit(0);

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.

The same script works fine on Linux.

This was tested with Windows Server 2008, IIS, PHP 5.2.13. But I have seen this on other Windows configurations as well.

Test script:
---------------
<?php
$cmd = "\"C:/Program Files/php/php.exe\" process.php";

$status;
$stdout = "";
$stderr = "";
$pipes = array();

$descriptors = array(
	0 => array("pipe", "r"),	// stdin
	1 => array("pipe", "w"),	// stdout
	2 => array("pipe", "w")		// stderr
	);
$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);
}

print_r(array(
	"status" => $status,
	"stdout" => $stdout,
	"stderr" => $stderr,
));
?>


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-02-19 14:37 UTC] nicolas dot sauveur at gmail dot com
This seems similar as https://bugs.php.net/bug.php?id=60120 .

Only partially fixed for me ( thus not fixed ) in php 5.3.9.
 [2012-04-08 21:21 UTC] seld@php.net
I could reproduce this on PHP 5.4.0 as soon as $data is longer than 4096 bytes.

With $data = str_repeat("a", 4097); in process.php it hangs forever, while with any number until 4096 it passes.
 [2012-04-09 12:33 UTC] pajoye@php.net
-Status: Open +Status: Verified
 [2012-04-09 12:33 UTC] pajoye@php.net
-PHP Version: 5.2.13 +PHP Version: *
 [2012-04-09 12:49 UTC] pajoye@php.net
-Assigned To: +Assigned To: ab
 [2012-04-09 12:49 UTC] pajoye@php.net
it seems that the issue is on main/streams.c:679

		if (stream->writepos - stream->readpos < (off_t)size) {

where writepos and readpos are equals.

Anatolyi, please take a look at it.
 [2012-04-09 12:52 UTC] pajoye@php.net
-Status: Verified +Status: Assigned
 [2012-04-12 14:41 UTC] andremiguelcruz at msn dot com
I hope this gets fixed soon both on 5.4 and 5.3.
Is very frustrating because I have this bug while using symfony2 with scss.
 [2013-03-16 03:15 UTC] hanskrentel at yahoo dot de
The problem with exactly 4097 bytes has just been reported here: 
https://bugs.php.net/bug.php?id=64438

It's a follow up to https://bugs.php.net/bug.php?id=60120 which is wrongly closed 
as resolved.

this and the many other issues show that the flaw is not fixed:

https://bugs.php.net/bug.php?id=51800
https://bugs.php.net/bug.php?id=60120
https://bugs.php.net/bug.php?id=64438
 [2013-05-06 07:47 UTC] ab@php.net
It hangs at http://lxr.php.net/xref/PHP_5_5/main/streams/plain_wrapper.c#348 , the 
read call doesn't return at some point. Setting the pipe mode to wb tells no 
difference. But I guess the cause is somewhere in the upper levels, may be in the 
descriptor options. So continuing to debug.
 [2013-05-06 16:55 UTC] ab@php.net
Could you please try this slightly modified php snippet?

============ START process.php ===============
<?php

$how_much = 10000;

$data0 = str_repeat("a", $how_much); 
$data1 = str_repeat("b", $how_much); 
fwrite(STDOUT, $data0);
fwrite(STDERR, $data1);

exit(0);
============ END process.php ===============

============ START 51800.php ===============
<?php
$cmd = "\"C:/php-sdk/php55/vc11/x86/php-src/Debug/php.exe\" process.php";

$status;
$stdout = "";
$stderr = "";
$pipes = array();

$descriptors = array(
	0 => array("pipe", "rb"),	// stdin
	1 => array("pipe", "wb"),	// stdout
	2 => array("pipe", "wb")		// stderr
	);
$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);
}

print_r(array(
	"status" => $status,
	"stdout" => $stdout,
	"stderr" => $stderr,
));
============ END 51800.php ===============

This bug might be pretty much not a php bug, but the consequence of the pipe 
nature.
 [2013-05-06 17:06 UTC] pajoye@php.net
It is a php bug, same kind of call using standalone C code works fine.
 [2013-05-08 06:33 UTC] pajoye@php.net
A good summary of the problem we are experiencing here:

http://blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx

The fix is not that easy. Either using overlapped/async IO or threads.
 [2013-10-16 18:42 UTC] imprec at gmail dot com
Hello,

what's the state on this bug? It's quite annoying. Using file handles as a workaround does not work very well on windows (see https://bugs.php.net/bug.php?id=65650).

Is there any plan to solve it? I'd be glad to contribute, but my skills are pretty bad at this level :/
 [2014-09-29 14:32 UTC] ab@php.net
Automatic comment on behalf of ab
Revision: http://git.php.net/?p=php-src.git;a=commit;h=0c982798e01e5a48765aa5352f96066e77e36efd
Log: Fixed bug #51800 proc_open on Windows hangs forever
 [2014-09-29 14:32 UTC] ab@php.net
-Status: Assigned +Status: Closed
 [2014-09-30 17:17 UTC] ab@php.net
Automatic comment on behalf of ab
Revision: http://git.php.net/?p=php-src.git;a=commit;h=0c982798e01e5a48765aa5352f96066e77e36efd
Log: Fixed bug #51800 proc_open on Windows hangs forever
 [2015-02-12 12:22 UTC] aserbulov at parallels dot com
Applied fix has a very bad side effect.
Let's rewrite process.php script:
---
sleep(60);
fwrite(STDOUT, 'done');
exit(0);
---

In this case you never get process output: feof($pipes[1]) will return true after ~18 seconds.
 [2019-06-23 16:28 UTC] nicolas dot grekas+php at gmail dot com
Would it be possible to implement non-blocking reads to work around this issue?
A working stream_select() on a pipe would allow writing libs that don't hit the issue. The current ways are hideous (piping to a temporary file...)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 10:01:29 2024 UTC