Bug #66437 [NEW]: proc_close misbehaves if proc_get_status was used
| From: | phpbugs2012 at joern dot heissler dot de | Date: | Tue, 07 Jan 2014 17:50:13 +0000 |
| Subject: | Bug #66437 [NEW]: proc_close misbehaves if proc_get_status was used | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-183630@lists.php.net to get a copy of this message | ||
From: phpbugs2012 at joern dot heissler dot de
Operating system: Linux
PHP version: 5.5.7
Package: Program Execution
Bug Type: Bug
Bug description:proc_close misbehaves if proc_get_status was used
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 bug report at https://bugs.php.net/bug.php?id=66437&edit=1
--
Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=66437&r=trysnapshot54
Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=66437&r=trysnapshot55
Try a snapshot (trunk): https://bugs.php.net/fix.php?id=66437&r=trysnapshottrunk
Fixed in SVN: https://bugs.php.net/fix.php?id=66437&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=66437&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=66437&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=66437&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=66437&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=66437&r=support
Expected behavior: https://bugs.php.net/fix.php?id=66437&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=66437&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=66437&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=66437&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=66437&r=php4
Daylight Savings: https://bugs.php.net/fix.php?id=66437&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=66437&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=66437&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=66437&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=66437&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=66437&r=mysqlcfg