Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8f437aa

Browse files
committed
Issue #22290: Fix error handling in the _posixsubprocess module.
* Don't call the garbage collector with an exception set: it causes an assertion to fail in debug mode. * Enhance also error handling if allocating an array for the executable list failed. * Add an unit test for 4 different errors in the _posixsubprocess module.
1 parent 340c749 commit 8f437aa

2 files changed

Lines changed: 47 additions & 6 deletions

File tree

Lib/test/test_subprocess.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,6 +2216,39 @@ def test_close_fds_after_preexec(self):
22162216

22172217
self.assertNotIn(fd, remaining_fds)
22182218

2219+
@support.cpython_only
2220+
def test_fork_exec(self):
2221+
# Issue #22290: fork_exec() must not crash on memory allocation failure
2222+
# or other errors
2223+
import _posixsubprocess
2224+
gc_enabled = gc.isenabled()
2225+
try:
2226+
# Use a preexec function and enable the garbage collector
2227+
# to force fork_exec() to re-enable the garbage collector
2228+
# on error.
2229+
func = lambda: None
2230+
gc.enable()
2231+
2232+
executable_list = "exec" # error: must be a sequence
2233+
2234+
for args, exe_list, cwd, env_list in (
2235+
(123, [b"exe"], None, [b"env"]),
2236+
([b"arg"], 123, None, [b"env"]),
2237+
([b"arg"], [b"exe"], 123, [b"env"]),
2238+
([b"arg"], [b"exe"], None, 123),
2239+
):
2240+
with self.assertRaises(TypeError):
2241+
_posixsubprocess.fork_exec(
2242+
args, exe_list,
2243+
True, [], cwd, env_list,
2244+
-1, -1, -1, -1,
2245+
1, 2, 3, 4,
2246+
True, True, func)
2247+
finally:
2248+
if not gc_enabled:
2249+
gc.disable()
2250+
2251+
22192252

22202253
@unittest.skipUnless(mswindows, "Windows specific tests")
22212254
class Win32ProcessTestCase(BaseTestCase):

Modules/_posixsubprocess.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
538538
int need_to_reenable_gc = 0;
539539
char *const *exec_array, *const *argv = NULL, *const *envp = NULL;
540540
Py_ssize_t arg_num;
541+
int import_lock_held = 0;
541542

542543
if (!PyArg_ParseTuple(
543544
args, "OOpOOOiiiiiiiiiiO:fork_exec",
@@ -590,10 +591,8 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
590591
}
591592

592593
exec_array = _PySequence_BytesToCharpArray(executable_list);
593-
if (!exec_array) {
594-
Py_XDECREF(gc_module);
595-
return NULL;
596-
}
594+
if (!exec_array)
595+
goto cleanup;
597596

598597
/* Convert args and env into appropriate arguments for exec() */
599598
/* These conversions are done in the parent process to avoid allocating
@@ -635,6 +634,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
635634
if (!preexec_fn_args_tuple)
636635
goto cleanup;
637636
_PyImport_AcquireLock();
637+
import_lock_held = 1;
638638
}
639639

640640
if (cwd_obj != Py_None) {
@@ -682,6 +682,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
682682
PyErr_SetString(PyExc_RuntimeError,
683683
"not holding the import lock");
684684
}
685+
import_lock_held = 0;
685686

686687
/* Parent process */
687688
if (envp)
@@ -704,18 +705,25 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
704705
return PyLong_FromPid(pid);
705706

706707
cleanup:
708+
if (import_lock_held)
709+
_PyImport_ReleaseLock();
707710
if (envp)
708711
_Py_FreeCharPArray(envp);
709712
if (argv)
710713
_Py_FreeCharPArray(argv);
711-
_Py_FreeCharPArray(exec_array);
714+
if (exec_array)
715+
_Py_FreeCharPArray(exec_array);
712716
Py_XDECREF(converted_args);
713717
Py_XDECREF(fast_args);
714718
Py_XDECREF(preexec_fn_args_tuple);
715719

716720
/* Reenable gc if it was disabled. */
717-
if (need_to_reenable_gc)
721+
if (need_to_reenable_gc) {
722+
PyObject *exctype, *val, *tb;
723+
PyErr_Fetch(&exctype, &val, &tb);
718724
_enable_gc(gc_module);
725+
PyErr_Restore(exctype, val, tb);
726+
}
719727
Py_XDECREF(gc_module);
720728
return NULL;
721729
}

0 commit comments

Comments
 (0)