[php-src] master: Merge branch 'PHP-8.6'
| From: | Ilia Alshanetsky | Date: | Sun, 04 Oct 2026 15:54:10 +0000 |
| Subject: | [php-src] master: Merge branch 'PHP-8.6' | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-141925@lists.php.net to get a copy of this message | ||
Author: Ilia Alshanetsky (iliaal)
Date: 2026-10-04T11:47:16-04:00
Commit: https://github.com/php/php-src/commit/1ee921c3ebb7262ab6f6ea95ae55f88237e2b14a
Raw diff: https://github.com/php/php-src/commit/1ee921c3ebb7262ab6f6ea95ae55f88237e2b14a.diff
Merge branch 'PHP-8.6'
* PHP-8.6:
ext/standard: Close owned proc_open descriptors on setup failure
Changed paths:
A ext/standard/tests/general_functions/proc_open_descriptor_0_setup_failure.phpt
A ext/standard/tests/general_functions/proc_open_socket_descriptor_0_setup_failure.phpt
M ext/standard/proc_open.c
Diff:
diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c
index 8bd3361f59cb..4fd24058f7cb 100644
--- a/ext/standard/proc_open.c
+++ b/ext/standard/proc_open.c
@@ -1185,8 +1185,9 @@ static void close_all_descriptors(descriptorspec_item *descriptors, int ndesc)
{
for (int i = 0; i < ndesc; i++) {
close_descriptor(descriptors[i].childend);
- if (descriptors[i].parentend)
+ if (descriptors[i].type != DESCRIPTOR_TYPE_STD) {
close_descriptor(descriptors[i].parentend);
+ }
}
}
diff --git a/ext/standard/tests/general_functions/proc_open_descriptor_0_setup_failure.phpt
b/ext/standard/tests/general_functions/proc_open_descriptor_0_setup_failure.phpt
new file mode 100644
index 000000000000..ea654b0f497a
--- /dev/null
+++ b/ext/standard/tests/general_functions/proc_open_descriptor_0_setup_failure.phpt
@@ -0,0 +1,29 @@
+--TEST--
+proc_open() closes descriptor 0 when setup fails after pipe allocation
+--SKIPIF--
+<?php
+if (!function_exists("proc_open")) {
+ die("skip proc_open() unavailable");
+}
+if (!@is_dir("/proc/self/fd")) {
+ die("skip requires /proc/self/fd");
+}
+?>
+--FILE--
+<?php
+$code = <<<'PHP'
+fclose(STDIN);
+var_dump(@proc_open("true", [0 => ["pipe", "w"], 1 =>
["bogus_type"]], $pipes));
+$fd = fopen("/dev/null", "r");
+var_dump(readlink("/proc/self/fd/0"));
+fclose($fd);
+PHP;
+$process = proc_open([PHP_BINARY, "-n", "-r", $code], [1 =>
["pipe", "w"]], $pipes);
+echo stream_get_contents($pipes[1]);
+fclose($pipes[1]);
+var_dump(proc_close($process));
+?>
+--EXPECT--
+bool(false)
+string(9) "/dev/null"
+int(0)
diff --git a/ext/standard/tests/general_functions/proc_open_socket_descriptor_0_setup_failure.phpt
b/ext/standard/tests/general_functions/proc_open_socket_descriptor_0_setup_failure.phpt
new file mode 100644
index 000000000000..88e4eee1b20b
--- /dev/null
+++ b/ext/standard/tests/general_functions/proc_open_socket_descriptor_0_setup_failure.phpt
@@ -0,0 +1,29 @@
+--TEST--
+proc_open() closes descriptor 0 when setup fails after socket allocation
+--SKIPIF--
+<?php
+if (!function_exists("proc_open")) {
+ die("skip proc_open() unavailable");
+}
+if (!@is_dir("/proc/self/fd")) {
+ die("skip requires /proc/self/fd");
+}
+?>
+--FILE--
+<?php
+$code = <<<'PHP'
+fclose(STDIN);
+var_dump(@proc_open("true", [0 => ["socket"], 1 =>
["bogus_type"]], $pipes));
+$fd = fopen("/dev/null", "r");
+var_dump(readlink("/proc/self/fd/0"));
+fclose($fd);
+PHP;
+$process = proc_open([PHP_BINARY, "-n", "-r", $code], [1 =>
["pipe", "w"]], $pipes);
+echo stream_get_contents($pipes[1]);
+fclose($pipes[1]);
+var_dump(proc_close($process));
+?>
+--EXPECT--
+bool(false)
+string(9) "/dev/null"
+int(0)