proc_close() returns raw signal number, indistinguishable from normal exit code
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- C
- Estrellas
- 40.4k
- Forks
- 8.2k
- Merge medio
- 2 d 13 h
- PR fusionados (30 d)
- 96
Descripción
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)
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Rastrea proc_close() en sistemas que no son Windows a través de waitpid() y los casos WIFEXITED(), WEXITSTATUS(), WIFSIGNALED() y WTERMSIG() descritos en el issue. Ejecuta la reproducción proporcionada de proc_open() con un proceso hijo SIGSEGV y verifica que la terminación por señal se pueda distinguir de un código de salida normal, manteniendo al mismo tiempo el comportamiento esperado en otras plataformas.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- c, php
- Área
- backend, operating-systems
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Estancado
- Claridad
- Bastante claro
- Aptitud para principiantes
- 45/100