Commit efc42033d54 for php.net

commit efc42033d54d0c3eeefd1c5ce8b197783846e635
Author: Weilin Du <108666168+LamentXU123@users.noreply.github.com>
Date:   Tue May 5 19:21:44 2026 +0800

    ext/pcntl: Ensure `$array` is a list array in `pcntl_exec` (#21951)

diff --git a/NEWS b/NEWS
index fe70343e839..5f0c155a3f7 100644
--- a/NEWS
+++ b/NEWS
@@ -85,6 +85,10 @@ PHP                                                                        NEWS
     list of candidate encodings (with 200,000+ entries). (Jordi Kroon)
   . mbregex has been deprecated. (youkidearitai)

+- PCNTL:
+  . pcntl_exec() now throws a ValueError if the $args array is not a list
+    array. (Weilin Du)
+
 - Mysqli:
   . Added mysqli_quote_string() and mysqli::quote_string(). (Kamil Tekiela)

diff --git a/UPGRADING b/UPGRADING
index fe44036383d..d271eb47f7d 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -37,6 +37,8 @@ PHP 8.6 UPGRADE NOTES
 - PCNTL:
   . pcntl_alarm() now raises a ValueError if the seconds argument is
     lower than zero or greater than platform's UINT_MAX.
+  . pcntl_exec() now raises a ValueError if the $args argument is not a list
+    array.

 - PCRE:
   . preg_grep() now returns false instead of a partial array when a PCRE
diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c
index e9453b21329..2ba732c4540 100644
--- a/ext/pcntl/pcntl.c
+++ b/ext/pcntl/pcntl.c
@@ -675,7 +675,11 @@ PHP_FUNCTION(pcntl_exec)
 	ZEND_PARSE_PARAMETERS_END();

 	if (args != NULL) {
-		// TODO Check array is a list?
+		if (!zend_array_is_list(Z_ARRVAL_P(args))) {
+			zend_argument_value_error(2, "must be a list array");
+			RETURN_THROWS();
+		}
+
 		/* Build argument list */
 		SEPARATE_ARRAY(args);
 		const HashTable *args_ht = Z_ARRVAL_P(args);
diff --git a/ext/pcntl/tests/pcntl_exec_list_args.phpt b/ext/pcntl/tests/pcntl_exec_list_args.phpt
new file mode 100644
index 00000000000..5cd8c0fbe22
--- /dev/null
+++ b/ext/pcntl/tests/pcntl_exec_list_args.phpt
@@ -0,0 +1,14 @@
+--TEST--
+pcntl_exec(): Argument array must be a list
+--EXTENSIONS--
+pcntl
+--FILE--
+<?php
+try {
+    pcntl_exec('cmd', ['opt' => '-n']);
+} catch (Throwable $e) {
+    echo $e::class, ': ', $e->getMessage(), "\n";
+}
+?>
+--EXPECT--
+ValueError: pcntl_exec(): Argument #2 ($args) must be a list array