Skip to content

Commit 347fc43

Browse files
authored
gh-143698: correctly check scheduler and setpgroup values for os.posix_spawn[p] (#143699)
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.
1 parent 20b1535 commit 347fc43

File tree

6 files changed

+46
-15
lines changed

6 files changed

+46
-15
lines changed

Lib/test/test_inspect/test_inspect.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6267,8 +6267,7 @@ def test_operator_module_has_signatures(self):
62676267
def test_os_module_has_signatures(self):
62686268
unsupported_signature = {'chmod', 'utime'}
62696269
unsupported_signature |= {name for name in
6270-
['get_terminal_size', 'link', 'posix_spawn', 'posix_spawnp',
6271-
'register_at_fork', 'startfile']
6270+
['get_terminal_size', 'link', 'register_at_fork', 'startfile']
62726271
if hasattr(os, name)}
62736272
self._test_module_has_signatures(os, unsupported_signature=unsupported_signature)
62746273

Lib/test/test_os/test_posix.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,6 +2008,11 @@ def test_setpgroup(self):
20082008
)
20092009
support.wait_process(pid, exitcode=0)
20102010

2011+
def test_setpgroup_allow_none(self):
2012+
path, args = self.NOOP_PROGRAM[0], self.NOOP_PROGRAM
2013+
pid = self.spawn_func(path, args, os.environ, setpgroup=None)
2014+
support.wait_process(pid, exitcode=0)
2015+
20112016
def test_setpgroup_wrong_type(self):
20122017
with self.assertRaises(TypeError):
20132018
self.spawn_func(sys.executable,
@@ -2108,6 +2113,20 @@ def test_setsigdef_wrong_type(self):
21082113
[sys.executable, "-c", "pass"],
21092114
os.environ, setsigdef=[signal.NSIG, signal.NSIG+1])
21102115

2116+
def test_scheduler_allow_none(self):
2117+
path, args = self.NOOP_PROGRAM[0], self.NOOP_PROGRAM
2118+
pid = self.spawn_func(path, args, os.environ, scheduler=None)
2119+
support.wait_process(pid, exitcode=0)
2120+
2121+
@support.subTests("scheduler", [object(), 1, [1, 2]])
2122+
def test_scheduler_wrong_type(self, scheduler):
2123+
path, args = self.NOOP_PROGRAM[0], self.NOOP_PROGRAM
2124+
with self.assertRaisesRegex(
2125+
TypeError,
2126+
"scheduler must be a tuple or None",
2127+
):
2128+
self.spawn_func(path, args, os.environ, scheduler=scheduler)
2129+
21112130
@requires_sched
21122131
@unittest.skipIf(sys.platform.startswith(('freebsd', 'netbsd')),
21132132
"bpo-34685: test can fail on BSD")
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Raise :exc:`TypeError` instead of :exc:`SystemError` when the *scheduler*
2+
in :func:`os.posix_spawn` or :func:`os.posix_spawnp` is not a tuple.
3+
Patch by Bénédikt Tran.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Allow *scheduler* and *setpgroup* arguments to be explicitly :const:`None`
2+
when calling :func:`os.posix_spawn` or :func:`os.posix_spawnp`. Patch by
3+
Bénédikt Tran.

Modules/clinic/posixmodule.c.h

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7611,6 +7611,7 @@ parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpg
76117611
PyObject *setsigdef, PyObject *scheduler,
76127612
posix_spawnattr_t *attrp)
76137613
{
7614+
assert(scheduler == NULL || scheduler == Py_None || PyTuple_Check(scheduler));
76147615
long all_flags = 0;
76157616

76167617
errno = posix_spawnattr_init(attrp);
@@ -7619,7 +7620,7 @@ parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpg
76197620
return -1;
76207621
}
76217622

7622-
if (setpgroup) {
7623+
if (setpgroup && setpgroup != Py_None) {
76237624
pid_t pgid = PyLong_AsPid(setpgroup);
76247625
if (pgid == (pid_t)-1 && PyErr_Occurred()) {
76257626
goto fail;
@@ -7692,7 +7693,7 @@ parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpg
76927693
}
76937694
#endif
76947695

7695-
if (scheduler) {
7696+
if (scheduler && scheduler != Py_None) {
76967697
#ifdef POSIX_SPAWN_SETSCHEDULER
76977698
PyObject *py_schedpolicy;
76987699
PyObject *schedparam_obj;
@@ -7917,6 +7918,12 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
79177918
goto exit;
79187919
}
79197920

7921+
if (scheduler && !PyTuple_Check(scheduler) && scheduler != Py_None) {
7922+
PyErr_Format(PyExc_TypeError,
7923+
"%s: scheduler must be a tuple or None", func_name);
7924+
goto exit;
7925+
}
7926+
79207927
argvlist = parse_arglist(argv, &argc);
79217928
if (argvlist == NULL) {
79227929
goto exit;
@@ -8028,7 +8035,7 @@ os.posix_spawn
80288035
*
80298036
file_actions: object(c_default='NULL') = ()
80308037
A sequence of file action tuples.
8031-
setpgroup: object = NULL
8038+
setpgroup: object(c_default='NULL') = None
80328039
The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
80338040
resetids: bool = False
80348041
If the value is `true` the POSIX_SPAWN_RESETIDS will be activated.
@@ -8038,7 +8045,7 @@ os.posix_spawn
80388045
The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
80398046
setsigdef: object(c_default='NULL') = ()
80408047
The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
8041-
scheduler: object = NULL
8048+
scheduler: object(c_default='NULL') = None
80428049
A tuple with the scheduler policy (optional) and parameters.
80438050

80448051
Execute the program specified by path in a new process.
@@ -8050,7 +8057,7 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
80508057
PyObject *setpgroup, int resetids, int setsid,
80518058
PyObject *setsigmask, PyObject *setsigdef,
80528059
PyObject *scheduler)
8053-
/*[clinic end generated code: output=14a1098c566bc675 input=808aed1090d84e33]*/
8060+
/*[clinic end generated code: output=14a1098c566bc675 input=69e7c9ebbdcf94a5]*/
80548061
{
80558062
return py_posix_spawn(0, module, path, argv, env, file_actions,
80568063
setpgroup, resetids, setsid, setsigmask, setsigdef,
@@ -8074,7 +8081,7 @@ os.posix_spawnp
80748081
*
80758082
file_actions: object(c_default='NULL') = ()
80768083
A sequence of file action tuples.
8077-
setpgroup: object = NULL
8084+
setpgroup: object(c_default='NULL') = None
80788085
The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
80798086
resetids: bool = False
80808087
If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.
@@ -8084,7 +8091,7 @@ os.posix_spawnp
80848091
The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
80858092
setsigdef: object(c_default='NULL') = ()
80868093
The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
8087-
scheduler: object = NULL
8094+
scheduler: object(c_default='NULL') = None
80888095
A tuple with the scheduler policy (optional) and parameters.
80898096

80908097
Execute the program specified by path in a new process.
@@ -8096,7 +8103,7 @@ os_posix_spawnp_impl(PyObject *module, path_t *path, PyObject *argv,
80968103
PyObject *setpgroup, int resetids, int setsid,
80978104
PyObject *setsigmask, PyObject *setsigdef,
80988105
PyObject *scheduler)
8099-
/*[clinic end generated code: output=7b9aaefe3031238d input=9e89e616116752a1]*/
8106+
/*[clinic end generated code: output=7b9aaefe3031238d input=a5c057527c6881a5]*/
81008107
{
81018108
return py_posix_spawn(1, module, path, argv, env, file_actions,
81028109
setpgroup, resetids, setsid, setsigmask, setsigdef,

0 commit comments

Comments
 (0)