diff --git a/NEWS b/NEWS index e027d6c139ee..cf2e1ab2e536 100644 --- a/NEWS +++ b/NEWS @@ -123,6 +123,8 @@ PHP NEWS in a php://filter URL. (Sjoerd Langkemper) . Improved performance of array_chunk() when not preserving keys. (mehmetcansahin) + . Fixed bug GH-21292 (proc_close() returns raw signal number, + indistinguishable from normal exit code). (Alies Lapatsin) - URI: . Fix casing of enum cases in UriHostType and UrlHostType to match the RFC diff --git a/UPGRADING b/UPGRADING index 46cf4cafab12..9f35859138dc 100644 --- a/UPGRADING +++ b/UPGRADING @@ -31,6 +31,16 @@ PHP 8.7 UPGRADE NOTES . The number of filters that can be chained in a php://filter URL is limited to 16 by default. Set the stream context option max_filter_count to change this. + . On Unix systems, proc_close() now reports termination by a signal as + 128 + the signal number, following the shell convention, instead of the + raw wait status (e.g. 137 instead of 9 for SIGKILL). This also applies when + proc_get_status() observed the termination first; previously proc_close() + returned -1 in that case. Normal exit codes are unchanged. + . On Unix systems, proc_get_status() now also caches the status of a child + terminated by a signal, as it does for normal exits since PHP 8.3. + Repeated calls keep reporting "signaled" => true and the "termsig" value, + and "cached" is true. Previously, calls after the first one reported + "signaled" => false and "termsig" => 0. ======================================== 2. New Features diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 4fd24058f7cb..9ecc57bcbac4 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -256,10 +256,10 @@ static pid_t waitpid_cached(php_process_handle *proc, int *wait_status, int opti pid_t wait_pid = waitpid(proc->child, wait_status, options); - /* The "exit" status is the final status of the process. + /* The "exit" and "terminated by signal" statuses are final statuses of the process. * If we were to cache the status unconditionally, * we would return stale statuses in the future after the process continues. */ - if (wait_pid > 0 && WIFEXITED(*wait_status)) { + if (wait_pid > 0 && (WIFEXITED(*wait_status) || WIFSIGNALED(*wait_status))) { proc->has_cached_exit_wait_status = true; proc->cached_exit_wait_status_value = *wait_status; } @@ -317,11 +317,13 @@ static void proc_open_rsrc_dtor(zend_resource *rsrc) if (wait_pid <= 0) { FG(pclose_ret) = -1; + } else if (WIFEXITED(wstatus)) { + FG(pclose_ret) = WEXITSTATUS(wstatus); + } else if (WIFSIGNALED(wstatus)) { + /* Follow the bash/shell convention: 128 + signal number */ + FG(pclose_ret) = 128 + WTERMSIG(wstatus); } else { - if (WIFEXITED(wstatus)) { - wstatus = WEXITSTATUS(wstatus); - } - FG(pclose_ret) = wstatus; + FG(pclose_ret) = -1; } #else diff --git a/ext/standard/tests/general_functions/bug39322.phpt b/ext/standard/tests/general_functions/bug39322.phpt index 162f2babdaac..cfa56de1264a 100644 --- a/ext/standard/tests/general_functions/bug39322.phpt +++ b/ext/standard/tests/general_functions/bug39322.phpt @@ -30,7 +30,7 @@ array(9) { ["pid"]=> int(%d) ["cached"]=> - bool(false) + bool(true) ["running"]=> bool(false) ["signaled"]=> diff --git a/ext/standard/tests/general_functions/gh21292.phpt b/ext/standard/tests/general_functions/gh21292.phpt new file mode 100644 index 000000000000..43c3dd00c7aa --- /dev/null +++ b/ext/standard/tests/general_functions/gh21292.phpt @@ -0,0 +1,56 @@ +--TEST-- +GH-21292 (proc_close() returns raw signal number, indistinguishable from normal exit code) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Killed by SIGKILL: +int(137) +Normal exit: +int(42) +int(9) +int(137) +Killed by SIGKILL, status polled before proc_close(): +bool(true) +int(9) +bool(true) +bool(true) +int(9) +int(137) diff --git a/ext/standard/tests/general_functions/proc_open02.phpt b/ext/standard/tests/general_functions/proc_open02.phpt index dd2e6902a411..864d1001930a 100644 --- a/ext/standard/tests/general_functions/proc_open02.phpt +++ b/ext/standard/tests/general_functions/proc_open02.phpt @@ -59,7 +59,7 @@ array(9) { ["pid"]=> int(%d) ["cached"]=> - bool(false) + bool(true) ["running"]=> bool(false) ["signaled"]=>