Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 8 additions & 6 deletions ext/standard/proc_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/tests/general_functions/bug39322.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ array(9) {
["pid"]=>
int(%d)
["cached"]=>
bool(false)
bool(true)
["running"]=>
bool(false)
["signaled"]=>
Expand Down
56 changes: 56 additions & 0 deletions ext/standard/tests/general_functions/gh21292.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
--TEST--
GH-21292 (proc_close() returns raw signal number, indistinguishable from normal exit code)
--SKIPIF--
<?php
if (PHP_OS_FAMILY === 'Windows') die('skip Not for Windows');
if (!is_executable('/bin/sh')) die('skip /bin/sh not available');
?>
--FILE--
<?php

function spawn(string $script) {
$process = proc_open(
['/bin/sh', '-c', $script],
[['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']],
$pipes
);
foreach ($pipes as $pipe) {
fclose($pipe);
}
return $process;
}

echo "Killed by SIGKILL:\n";
var_dump(proc_close(spawn('kill -9 $$')));

echo "Normal exit:\n";
var_dump(proc_close(spawn('exit 42')));
var_dump(proc_close(spawn('exit 9')));
var_dump(proc_close(spawn('exit 137')));

echo "Killed by SIGKILL, status polled before proc_close():\n";
$process = spawn('kill -9 $$');
for ($i = 0; $i < 500 && proc_get_status($process)['running']; $i++) {
usleep(10000);
}
$status = proc_get_status($process);
var_dump($status['signaled'], $status['termsig']);
$status = proc_get_status($process);
var_dump($status['cached'], $status['signaled'], $status['termsig']);
var_dump(proc_close($process));

?>
--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)
2 changes: 1 addition & 1 deletion ext/standard/tests/general_functions/proc_open02.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ array(9) {
["pid"]=>
int(%d)
["cached"]=>
bool(false)
bool(true)
["running"]=>
bool(false)
["signaled"]=>
Expand Down
Loading