https://github.com/python/cpython/commit/dcf96d0ed6641e6fa6cd7df23d4ebf2bc3280c1b
commit: dcf96d0ed6641e6fa6cd7df23d4ebf2bc3280c1b
branch: 3.14
author: Bénédikt Tran <[email protected]>
committer: picnixz <[email protected]>
date: 2026-02-21T16:04:31+01:00
summary:

[3.14] gh-143698: correctly check `scheduler` and `setpgroup` values for 
`os.posix_spawn[p]` (GH-143699) (#145073)

Fix an issue where passing invalid arguments to `os.posix_spawn[p]` functions
raised a SystemError instead of a TypeError, and allow to explicitly use `None`
for `scheduler` and `setpgroup` as specified in the docs.

(cherry picked from commit 347fc438cf903c1d7fa5063464ae2e93c11b2232)

files:
A Misc/NEWS.d/next/Library/2026-01-11-16-59-22.gh-issue-143698.b-Cpeb.rst
A Misc/NEWS.d/next/Library/2026-01-11-18-35-52.gh-issue-143698.gXDzsJ.rst
M Lib/test/test_inspect/test_inspect.py
M Lib/test/test_posix.py
M Modules/clinic/posixmodule.c.h
M Modules/posixmodule.c

diff --git a/Lib/test/test_inspect/test_inspect.py 
b/Lib/test/test_inspect/test_inspect.py
index 35e31cd5ed1cf4..28acb2a45a31b7 100644
--- a/Lib/test/test_inspect/test_inspect.py
+++ b/Lib/test/test_inspect/test_inspect.py
@@ -6203,8 +6203,7 @@ def test_operator_module_has_signatures(self):
     def test_os_module_has_signatures(self):
         unsupported_signature = {'chmod', 'utime'}
         unsupported_signature |= {name for name in
-            ['get_terminal_size', 'link', 'posix_spawn', 'posix_spawnp',
-             'register_at_fork', 'startfile']
+            ['get_terminal_size', 'link', 'register_at_fork', 'startfile']
             if hasattr(os, name)}
         self._test_module_has_signatures(os, 
unsupported_signature=unsupported_signature)
 
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
index f51cdd26df7da5..a895d57d1ffec1 100644
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -1933,6 +1933,11 @@ def test_setpgroup(self):
         )
         support.wait_process(pid, exitcode=0)
 
+    def test_setpgroup_allow_none(self):
+        path, args = self.NOOP_PROGRAM[0], self.NOOP_PROGRAM
+        pid = self.spawn_func(path, args, os.environ, setpgroup=None)
+        support.wait_process(pid, exitcode=0)
+
     def test_setpgroup_wrong_type(self):
         with self.assertRaises(TypeError):
             self.spawn_func(sys.executable,
@@ -2033,6 +2038,20 @@ def test_setsigdef_wrong_type(self):
                             [sys.executable, "-c", "pass"],
                             os.environ, setsigdef=[signal.NSIG, signal.NSIG+1])
 
+    def test_scheduler_allow_none(self):
+        path, args = self.NOOP_PROGRAM[0], self.NOOP_PROGRAM
+        pid = self.spawn_func(path, args, os.environ, scheduler=None)
+        support.wait_process(pid, exitcode=0)
+
+    @support.subTests("scheduler", [object(), 1, [1, 2]])
+    def test_scheduler_wrong_type(self, scheduler):
+        path, args = self.NOOP_PROGRAM[0], self.NOOP_PROGRAM
+        with self.assertRaisesRegex(
+            TypeError,
+            "scheduler must be a tuple or None",
+        ):
+            self.spawn_func(path, args, os.environ, scheduler=scheduler)
+
     @requires_sched
     @unittest.skipIf(sys.platform.startswith(('freebsd', 'netbsd')),
                      "bpo-34685: test can fail on BSD")
diff --git 
a/Misc/NEWS.d/next/Library/2026-01-11-16-59-22.gh-issue-143698.b-Cpeb.rst 
b/Misc/NEWS.d/next/Library/2026-01-11-16-59-22.gh-issue-143698.b-Cpeb.rst
new file mode 100644
index 00000000000000..05dc4941c98a83
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-01-11-16-59-22.gh-issue-143698.b-Cpeb.rst
@@ -0,0 +1,3 @@
+Raise :exc:`TypeError` instead of :exc:`SystemError` when the *scheduler*
+in :func:`os.posix_spawn` or :func:`os.posix_spawnp` is not a tuple.
+Patch by Bénédikt Tran.
diff --git 
a/Misc/NEWS.d/next/Library/2026-01-11-18-35-52.gh-issue-143698.gXDzsJ.rst 
b/Misc/NEWS.d/next/Library/2026-01-11-18-35-52.gh-issue-143698.gXDzsJ.rst
new file mode 100644
index 00000000000000..5f95b0de7d8895
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-01-11-18-35-52.gh-issue-143698.gXDzsJ.rst
@@ -0,0 +1,3 @@
+Allow *scheduler* and *setpgroup* arguments to be explicitly :const:`None`
+when calling :func:`os.posix_spawn` or :func:`os.posix_spawnp`. Patch by
+Bénédikt Tran.
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index 87a17935507b9c..1c7a860e1ec8ca 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -3845,8 +3845,8 @@ os_execve(PyObject *module, PyObject *const *args, 
Py_ssize_t nargs, PyObject *k
 
 PyDoc_STRVAR(os_posix_spawn__doc__,
 "posix_spawn($module, path, argv, env, /, *, file_actions=(),\n"
-"            setpgroup=<unrepresentable>, resetids=False, setsid=False,\n"
-"            setsigmask=(), setsigdef=(), scheduler=<unrepresentable>)\n"
+"            setpgroup=None, resetids=False, setsid=False,\n"
+"            setsigmask=(), setsigdef=(), scheduler=None)\n"
 "--\n"
 "\n"
 "Execute the program specified by path in a new process.\n"
@@ -3998,8 +3998,8 @@ os_posix_spawn(PyObject *module, PyObject *const *args, 
Py_ssize_t nargs, PyObje
 
 PyDoc_STRVAR(os_posix_spawnp__doc__,
 "posix_spawnp($module, path, argv, env, /, *, file_actions=(),\n"
-"             setpgroup=<unrepresentable>, resetids=False, setsid=False,\n"
-"             setsigmask=(), setsigdef=(), scheduler=<unrepresentable>)\n"
+"             setpgroup=None, resetids=False, setsid=False,\n"
+"             setsigmask=(), setsigdef=(), scheduler=None)\n"
 "--\n"
 "\n"
 "Execute the program specified by path in a new process.\n"
@@ -13476,4 +13476,4 @@ os__emscripten_log(PyObject *module, PyObject *const 
*args, Py_ssize_t nargs, Py
 #ifndef OS__EMSCRIPTEN_LOG_METHODDEF
     #define OS__EMSCRIPTEN_LOG_METHODDEF
 #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */
-/*[clinic end generated code: output=9e5f9b9ce732a534 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=291f607b7a26ca5e input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index cb3a62d211ac55..cb4fe1e6c8ca03 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -7155,6 +7155,7 @@ parse_posix_spawn_flags(PyObject *module, const char 
*func_name, PyObject *setpg
                         PyObject *setsigdef, PyObject *scheduler,
                         posix_spawnattr_t *attrp)
 {
+    assert(scheduler == NULL || scheduler == Py_None || 
PyTuple_Check(scheduler));
     long all_flags = 0;
 
     errno = posix_spawnattr_init(attrp);
@@ -7163,7 +7164,7 @@ parse_posix_spawn_flags(PyObject *module, const char 
*func_name, PyObject *setpg
         return -1;
     }
 
-    if (setpgroup) {
+    if (setpgroup && setpgroup != Py_None) {
         pid_t pgid = PyLong_AsPid(setpgroup);
         if (pgid == (pid_t)-1 && PyErr_Occurred()) {
             goto fail;
@@ -7236,7 +7237,7 @@ parse_posix_spawn_flags(PyObject *module, const char 
*func_name, PyObject *setpg
     }
 #endif
 
-    if (scheduler) {
+    if (scheduler && scheduler != Py_None) {
 #ifdef POSIX_SPAWN_SETSCHEDULER
         PyObject *py_schedpolicy;
         PyObject *schedparam_obj;
@@ -7461,6 +7462,12 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, 
path_t *path, PyObject *a
         goto exit;
     }
 
+    if (scheduler && !PyTuple_Check(scheduler) && scheduler != Py_None) {
+        PyErr_Format(PyExc_TypeError,
+                     "%s: scheduler must be a tuple or None", func_name);
+        goto exit;
+    }
+
     argvlist = parse_arglist(argv, &argc);
     if (argvlist == NULL) {
         goto exit;
@@ -7572,7 +7579,7 @@ os.posix_spawn
     *
     file_actions: object(c_default='NULL') = ()
         A sequence of file action tuples.
-    setpgroup: object = NULL
+    setpgroup: object(c_default='NULL') = None
         The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
     resetids: bool = False
         If the value is `true` the POSIX_SPAWN_RESETIDS will be activated.
@@ -7582,7 +7589,7 @@ os.posix_spawn
         The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
     setsigdef: object(c_default='NULL') = ()
         The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
-    scheduler: object = NULL
+    scheduler: object(c_default='NULL') = None
         A tuple with the scheduler policy (optional) and parameters.
 
 Execute the program specified by path in a new process.
@@ -7594,7 +7601,7 @@ os_posix_spawn_impl(PyObject *module, path_t *path, 
PyObject *argv,
                     PyObject *setpgroup, int resetids, int setsid,
                     PyObject *setsigmask, PyObject *setsigdef,
                     PyObject *scheduler)
-/*[clinic end generated code: output=14a1098c566bc675 input=808aed1090d84e33]*/
+/*[clinic end generated code: output=14a1098c566bc675 input=69e7c9ebbdcf94a5]*/
 {
     return py_posix_spawn(0, module, path, argv, env, file_actions,
                           setpgroup, resetids, setsid, setsigmask, setsigdef,
@@ -7618,7 +7625,7 @@ os.posix_spawnp
     *
     file_actions: object(c_default='NULL') = ()
         A sequence of file action tuples.
-    setpgroup: object = NULL
+    setpgroup: object(c_default='NULL') = None
         The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
     resetids: bool = False
         If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.
@@ -7628,7 +7635,7 @@ os.posix_spawnp
         The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
     setsigdef: object(c_default='NULL') = ()
         The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
-    scheduler: object = NULL
+    scheduler: object(c_default='NULL') = None
         A tuple with the scheduler policy (optional) and parameters.
 
 Execute the program specified by path in a new process.
@@ -7640,7 +7647,7 @@ os_posix_spawnp_impl(PyObject *module, path_t *path, 
PyObject *argv,
                      PyObject *setpgroup, int resetids, int setsid,
                      PyObject *setsigmask, PyObject *setsigdef,
                      PyObject *scheduler)
-/*[clinic end generated code: output=7b9aaefe3031238d input=9e89e616116752a1]*/
+/*[clinic end generated code: output=7b9aaefe3031238d input=a5c057527c6881a5]*/
 {
     return py_posix_spawn(1, module, path, argv, env, file_actions,
                           setpgroup, resetids, setsid, setsigmask, setsigdef,

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to