| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 340c749 commit 8f437aa
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2216,6 +2216,39 @@ def test_close_fds_after_preexec(self): | |||
| 2216 | 2216 | ||
| 2217 | 2217 | self.assertNotIn(fd, remaining_fds) | |
| 2218 | 2218 | ||
| 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 | + | ||
| 2219 | 2252 | ||
| 2220 | 2253 | @unittest.skipUnless(mswindows, "Windows specific tests") | |
| 2221 | 2254 | class Win32ProcessTestCase(BaseTestCase): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -538,6 +538,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args) | |||
| 538 | 538 | int need_to_reenable_gc = 0; | |
| 539 | 539 | char *const *exec_array, *const *argv = NULL, *const *envp = NULL; | |
| 540 | 540 | Py_ssize_t arg_num; | |
| 541 | + int import_lock_held = 0; | ||
| 541 | 542 | ||
| 542 | 543 | if (!PyArg_ParseTuple( | |
| 543 | 544 | args, "OOpOOOiiiiiiiiiiO:fork_exec", | |
@@ -590,10 +591,8 @@ subprocess_fork_exec(PyObject* self, PyObject *args) | |||
| 590 | 591 | } | |
| 591 | 592 | ||
| 592 | 593 | 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; | ||
| 597 | 596 | ||
| 598 | 597 | /* Convert args and env into appropriate arguments for exec() */ | |
| 599 | 598 | /* These conversions are done in the parent process to avoid allocating | |
@@ -635,6 +634,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args) | |||
| 635 | 634 | if (!preexec_fn_args_tuple) | |
| 636 | 635 | goto cleanup; | |
| 637 | 636 | _PyImport_AcquireLock(); | |
| 637 | + import_lock_held = 1; | ||
| 638 | 638 | } | |
| 639 | 639 | ||
| 640 | 640 | if (cwd_obj != Py_None) { | |
@@ -682,6 +682,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args) | |||
| 682 | 682 | PyErr_SetString(PyExc_RuntimeError, | |
| 683 | 683 | "not holding the import lock"); | |
| 684 | 684 | } | |
| 685 | + import_lock_held = 0; | ||
| 685 | 686 | ||
| 686 | 687 | /* Parent process */ | |
| 687 | 688 | if (envp) | |
@@ -704,18 +705,25 @@ subprocess_fork_exec(PyObject* self, PyObject *args) | |||
| 704 | 705 | return PyLong_FromPid(pid); | |
| 705 | 706 | ||
| 706 | 707 | cleanup: | |
| 708 | + if (import_lock_held) | ||
| 709 | + _PyImport_ReleaseLock(); | ||
| 707 | 710 | if (envp) | |
| 708 | 711 | _Py_FreeCharPArray(envp); | |
| 709 | 712 | if (argv) | |
| 710 | 713 | _Py_FreeCharPArray(argv); | |
| 711 | - _Py_FreeCharPArray(exec_array); | ||
| 714 | + if (exec_array) | ||
| 715 | + _Py_FreeCharPArray(exec_array); | ||
| 712 | 716 | Py_XDECREF(converted_args); | |
| 713 | 717 | Py_XDECREF(fast_args); | |
| 714 | 718 | Py_XDECREF(preexec_fn_args_tuple); | |
| 715 | 719 | ||
| 716 | 720 | /* 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); | ||
| 718 | 724 | _enable_gc(gc_module); | |
| 725 | + PyErr_Restore(exctype, val, tb); | ||
| 726 | + } | ||
| 719 | 727 | Py_XDECREF(gc_module); | |
| 720 | 728 | return NULL; | |
| 721 | 729 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments