Bug #66437 [Com]: proc_close misbehaves if proc_get_status was used

From: Date: Wed, 08 Jan 2014 00:22:56 +0000
Subject: Bug #66437 [Com]: proc_close misbehaves if proc_get_status was used
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-183636@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=66437&edit=1 ID: 66437 Comment by: phpbugs2012 at joern dot heissler dot de Reported by: phpbugs2012 at joern dot heissler dot de Summary: proc_close misbehaves if proc_get_status was used Status: Feedback Type: Bug Package: Program Execution Operating System: Linux PHP Version: 5.5.7 Block user comment: N Private report: N New Comment: Thanks for the really quick patch! ext/standard/file.c can't be compiled, popen seems to use the same global vars. Same for main/streams/streams.c I commented out the noncompiling code so that I can test the proc_… functions. I still see wait4 (i.e. waitpid) in the strace for proc_get_status after the child terminated. Previous Comments: ------------------------------------------------------------------------ [2014-01-07 20:19:28] krakjoe@php.net Please test attached patch. ------------------------------------------------------------------------ [2014-01-07 20:18:49] krakjoe@php.net The following patch has been added/updated: Patch Name: proc-open-stuff.patch Revision: 1389125929 URL: https://bugs.php.net/patch-display.php?bug=66437&patch=proc-open-stuff.patch&revision=1389125929 ------------------------------------------------------------------------ [2014-01-07 17:50:12] phpbugs2012 at joern dot heissler dot de Description: ------------ I have several sub processes (created with proc_open) which terminate in unspecified order. To know which processes terminate, I check each with proc_get_status. When `running' is false, I call proc_close to free the resources. proc_close always returns -1 instead of the real exit status. Seems to be an old bug (http://de2.php.net/manual/en/function.proc-close.php#83622), but I couldn't find a bug report yet. I'm not too familiar with php's source code, but this is what I think happens: proc_get_status calls waitpid, reaping the child zombie process. proc_close diminishes the reference counter on the process handle which causes the destructor (proc_open_rsrc_dtor) to do its job. HAVE_SYS_WAIT_H should be defined on my system, so once again waitpid is called. On a process which doesn't exist anymore. waitpid returns -1 with errno == ECHILD. The status -1 is stored in a global variable file_globals.pclose_ret and returned by proc_close. The code should be rewritten. At least two things can go wrong: * proc_close can return a wrong status (-1) when proc_get_status or another wait/waitpid function was called * If a new process with the same process id came into existence between proc_get_status and proc_close, proc_close may hang. Suggested fix: proc_close and proc_get_status should call a common function which calls waitpid (with or without WNOHANG etc.). The returned status is stored in the resource object, not globally. When waitpid succeeded before, it must not be called again, the status can be taken from the saved data instead. Test script: --------------- <?php $p = proc_open('sleep 1', array(), $foo); do { usleep(100000); $s = proc_get_status($p); echo $s['running'] ? 'Running' : 'Finished', PHP_EOL; } while ($s['running']); $q = proc_open('sleep 3600', array(), $foo); echo proc_close($p), PHP_EOL; Expected result: ---------------- Running Running Running ... Finished 0 Actual result: -------------- Running Running Running ... Finished -1 or, if you're unlucky, the proc_close will hang for an hour if $q has the same process ID that $p had before. ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=66437&edit=1

« previous php.bugs (#183636) next »