proc_close() returns raw signal number, indistinguishable from normal exit code
Personne n'a encore pris cette issue.
- Langage dominant
- C
- Étoiles
- 40.4k
- Forks
- 8.2k
- Merge moyen
- 2 j 13 h
- PR mergées (30 j)
- 96
Description
Description
On non-Windows systems, when a child process opened via proc_open() is killed by a signal, proc_close() returns the raw signal number (e.g. 11 for SIGSEGV) rather than following the Unix convention of 128 + signal (e.g. 139).
This makes it impossible for PHP userland code to distinguish between "process exited normally with code 11" and "process was killed by SIGSEGV".
Underlying cause
Internally, proc_close() calls waitpid() which returns an encoded status. The C macros WIFEXITED()/WEXITSTATUS() and WIFSIGNALED()/WTERMSIG() exist to decode this, but proc_close() does not use them to differentiate the two cases. It effectively passes back a value that loses the signal/exit distinction.
PHP's own pcntl_waitpid() + pcntl_wifexited() + pcntl_wtermsig() handle this correctly, but pcntl is not always available, and proc_close() is the standard way to get the exit status of a proc_open() process.
Reproduction
<?php
// Child script that triggers SIGSEGV
$child = '<?php posix_kill(posix_getpid(), 11);';
$process = proc_open(
[PHP_BINARY, '-r', $child],
[],
$pipes
);
$exitCode = proc_close($process);
// Expected: 139 (128 + 11, following bash/Unix convention)
// Actual: 11 (raw signal number, same as a normal exit code)
echo "Exit code: $exitCode\n";
echo "Is this SIGSEGV or a normal exit(11)? Impossible to tell.\n";
Expected behavior
proc_close() should return 128 + signal_number when the child was killed by a signal, consistent with how bash and other Unix shells report signal termination via $?. This would allow userland code to detect crashes.
Alternatively, expose the signal information through a separate mechanism (e.g. an optional by-reference parameter, or a new proc_exit_status() function).
Real-world impact
This affects tools that use proc_open() to spawn child processes, notably composer/xdebug-handler which restarts PHP processes. When the child crashes (e.g. due to a PHP JIT bug triggering SIGSEGV), the parent receives exit code 11 with no way to detect it was a signal — leading to silent, misleading failures in tools like Psalm, PHPStan, and Composer.
- Related upstream fix: https://github.com/composer/xdebug-handler/pull/162
- Downstream report: https://github.com/vimeo/psalm/issues/11679
PHP Version
Tested on PHP 8.4 and 8.5, but the behavior has existed since proc_open was introduced.
Operating System
Linux / macOS (any non-Windows POSIX system)
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Suivez proc_close() sur les systèmes non-Windows via waitpid() et les cas WIFEXITED(), WEXITSTATUS(), WIFSIGNALED() et WTERMSIG() décrits dans l’issue. Exécutez la reproduction fournie de proc_open() avec un processus enfant SIGSEGV et vérifiez que la terminaison par signal peut être distinguée d’un code de sortie normal, tout en préservant le comportement attendu sur les autres plateformes.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- c, php
- Domaine
- backend, operating-systems
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 45/100