php / php/php-src

proc_close() returns raw signal number, indistinguishable from normal exit code

Ouverte
#21,292 1 commentaire 2 réactions 0 personnes assignées Voir sur GitHub

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.

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

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. 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

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.