|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2005-10-09 18:23 UTC] e-t172 at e-t172 dot net
Description:
------------
(i am french, sorry for my bad english)
1. Open two processes with proc_open()
2. Try to close them : it works only if you close the second one first, otherwise it hangs
Reproduce code:
---------------
<?php
echo('Opening process 1'."\n");
$process1 = proc_open('cat', array(0 => array('pipe', 'r'), 1 => array('pipe', 'r')), $pipes1);
echo('Opening process 2'."\n");
$process2 = proc_open('cat', array(0 => array('pipe', 'r'), 1 => array('pipe', 'r')), $pipes2);
// WORKS :
//echo('Closing process 2'."\n");
//fclose($pipes2[0]); fclose($pipes2[1]); proc_close($process2);
//echo('Closing process 1'."\n");
//fclose($pipes1[0]); fclose($pipes1[1]); proc_close($process1);
// DOESN'T WORK :
echo('Closing process 1'."\n");
fclose($pipes1[0]); fclose($pipes1[1]); proc_close($process1);
echo('Closing process 2'."\n");
fclose($pipes2[0]); fclose($pipes2[1]); proc_close($process2);
?>
Expected result:
----------------
$ php -f test.php
Opening process 1
Opening process 2
Closing process 1
Closing process 2
$
Actual result:
--------------
$ php -f test.php
Opening process 1
Opening process 2
Closing process 1
(HANGS)
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Oct 24 11:00:02 2025 UTC |
Same problem with 5.1.3RC4-dev (latest CVS snapshot at the moment) on Linux/i386. I independently reproduced the bug with the following piece of code: error_reporting(E_ALL); $spec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w") ); $p1 = proc_open("/bin/cat", $spec, $fd1); $p2 = proc_open("/bin/cat", $spec, $fd2); fclose($fd1[0]); fclose($fd1[1]); fclose($fd1[2]); echo "closing p1... "; flush(); proc_close($p1); echo "success\n"; flush(); This code hangs in proc_close(). This doesn't happen if the second proc_open() is commented. Although the parent process seems to correctly close all pipes, the child process still remains blocked in read(0,...).Actually yes, there is a severe pipe setup problem. The problem is that the second spawned process inherits the descriptor of parent end of pipe to the first spawned process, created when setting up the process1 pipes. Since PHP doesn't set the close-on-exec flag, the descriptor stays open in process2. So, when the parent-end of pipes1[0] is closed in master script, the descriptor is still open by process2, thus the pipe write end is not closed yet and thus cat in process1 doesn't end. Note this is also potential security problem, since the second process is able to send data to the first. Fix: --- ext/standard/proc_open.c.orig 2006-05-28 19:10:35.000000000 +0200 +++ ext/standard/proc_open.c @@ -929,6 +929,16 @@ PHP_FUNCTION(proc_open) descriptors[i].mode_flags), mode_string, NULL); #else stream = php_stream_fopen_from_fd(descriptors[i].parentend, mode_string, NULL); + +#if defined(F_SETFD) && defined(FD_CLOEXEC) + /* + * Mark the descriptor close-on-exec, so that it + * it won't be inherited by potential other children. + * This avoids first child deadlock on proc_close(). + */ + fcntl(descriptors[i].parentend, F_SETFD, FD_CLOEXEC); +#endif + #endif if (stream) { zval *retfp;