Detect crash signals in restarted process exit code#162
Detect crash signals in restarted process exit code#162alies-dev wants to merge 3 commits intocomposer:mainfrom
Conversation
On non-Windows systems, proc_close() returns the raw signal number when the child process is killed by a signal (e.g. 11 for SIGSEGV). This is indistinguishable from a normal exit code, causing consumers to silently exit with a misleading code and no error output. Detect common crash signals (SIGILL, SIGABRT, SIGFPE, SIGSEGV) and: - Log a warning via the existing Status notification system - Normalize the exit code to the Unix convention of 128 + signal
|
For reference, I've also reported the underlying PHP issue: php/php-src#21292
|
|
FYI — $status = proc_get_status($process);
while ($status['running']) {
usleep(1000);
$status = proc_get_status($process);
}
if ($status['signaled']) {
$exitCode = 128 + $status['termsig'];
} else {
$exitCode = $status['exitcode'];
}
proc_close($process);I also opened a fix on the php-src side (php/php-src#21293) to make |
Instead of guessing based on a hardcoded list of signal numbers (which are also valid normal exit codes), use proc_get_status() which provides definitive signaled/termsig fields. This works on all PHP versions and detects any signal, not just the four previously hardcoded ones.
5622113 to
ec41d2b
Compare
The previous approach called proc_get_status() once before proc_close(), but the process could still be running at that point, causing the signal detection to be skipped entirely. Now polls proc_get_status() until the process exits, then reads the definitive signaled/termsig fields. proc_close() is called only to free the resource.
ec41d2b to
d778836
Compare
| $process = proc_open($cmd, [], $pipes); | ||
| if (is_resource($process)) { | ||
| $exitCode = proc_close($process); | ||
| // Poll proc_get_status until the process exits, so we can |
There was a problem hiding this comment.
i would love to see a test failing without this. otherwise, it will be fragile and may break again any time in future
|
Thanks but I think it is better to let PHP sort this out. |
Summary
On non-Windows systems,
proc_close()returns the raw signal number when the child process is killed by a signal (e.g. 11 forSIGSEGV). This is indistinguishable from a normal exit code, causing consumers to silently exit with a misleading code and no diagnostic output.This PR uses
proc_get_status()— which provides definitivesignaledandtermsigfields — to reliably detect when the child process was killed by a signal, then normalizes the exit code to the Unix convention of128 + signal.Why proc_get_status() instead of guessing
The previous approach hardcoded known signal numbers (4, 6, 8, 11) and assumed those exit codes meant a signal death. But those are also valid normal exit codes —
exit(11)would be misidentified as SIGSEGV.proc_get_status()returns separatesignaled(bool) andtermsig(int) fields that definitively distinguish signal deaths from normal exits. This works on all PHP versions and handles any signal.Also filed php/php-src#21293 to fix
proc_close()itself, but that would only help on future PHP versions.Context
Discovered while investigating vimeo/psalm#11679, where Psalm's restarted process crashes with
SIGSEGVdue to a PHP JIT bug, butproc_close()returns11— silently producing a misleading exit code.Before
After