| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1512,6 +1512,22 @@ def raise_runtime_error(): | |||
| 1512 | 1512 | if not enabled: | |
| 1513 | 1513 | gc.disable() | |
| 1514 | 1514 | ||
| 1515 | + def test_preexec_fork_failure(self): | ||
| 1516 | + # The internal code did not preserve the previous exception when | ||
| 1517 | + # re-enabling garbage collection | ||
| 1518 | + try: | ||
| 1519 | + from resource import getrlimit, setrlimit, RLIMIT_NPROC | ||
| 1520 | + except ImportError as err: | ||
| 1521 | + self.skipTest(err) # RLIMIT_NPROC is specific to Linux and BSD | ||
| 1522 | + limits = getrlimit(RLIMIT_NPROC) | ||
| 1523 | + [_, hard] = limits | ||
| 1524 | + setrlimit(RLIMIT_NPROC, (0, hard)) | ||
| 1525 | + self.addCleanup(setrlimit, RLIMIT_NPROC, limits) | ||
| 1526 | + # Forking should raise EAGAIN, translated to BlockingIOError | ||
| 1527 | + with self.assertRaises(BlockingIOError): | ||
| 1528 | + subprocess.call([sys.executable, '-c', ''], | ||
| 1529 | + preexec_fn=lambda: None) | ||
| 1530 | + | ||
| 1515 | 1531 | def test_args_string(self): | |
| 1516 | 1532 | # args is a string | |
| 1517 | 1533 | fd, fname = tempfile.mkstemp() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,6 +22,9 @@ Core and Builtins | |||
| 22 | 22 | Library | |
| 23 | 23 | ------- | |
| 24 | 24 | ||
| 25 | + - Issue #25764: In the subprocess module, preserve any exception caused by | ||
| 26 | + fork() failure when preexec_fn is used. | ||
| 27 | + | ||
| 25 | 28 | - Issue #6478: _strptime's regexp cache now is reset after changing timezone | |
| 26 | 29 | with time.tzset(). | |
| 27 | 30 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -47,17 +47,25 @@ | |||
| 47 | 47 | #define POSIX_CALL(call) do { if ((call) == -1) goto error; } while (0) | |
| 48 | 48 | ||
| 49 | 49 | ||
| 50 | - /* Given the gc module call gc.enable() and return 0 on success. */ | ||
| 50 | + /* If gc was disabled, call gc.enable(). Return 0 on success. */ | ||
| 51 | 51 | static int | |
| 52 | - _enable_gc(PyObject *gc_module) | ||
| 52 | + _enable_gc(int need_to_reenable_gc, PyObject *gc_module) | ||
| 53 | 53 | { | |
| 54 | 54 | PyObject *result; | |
| 55 | 55 | _Py_IDENTIFIER(enable); | |
| 56 | + PyObject *exctype, *val, *tb; | ||
| 56 | 57 | ||
| 57 | - result = _PyObject_CallMethodId(gc_module, &PyId_enable, NULL); | ||
| 58 | - if (result == NULL) | ||
| 59 | - return 1; | ||
| 60 | - Py_DECREF(result); | ||
| 58 | + if (need_to_reenable_gc) { | ||
| 59 | + PyErr_Fetch(&exctype, &val, &tb); | ||
| 60 | + result = _PyObject_CallMethodId(gc_module, &PyId_enable, NULL); | ||
| 61 | + if (exctype != NULL) { | ||
| 62 | + PyErr_Restore(exctype, val, tb); | ||
| 63 | + } | ||
| 64 | + if (result == NULL) { | ||
| 65 | + return 1; | ||
| 66 | + } | ||
| 67 | + Py_DECREF(result); | ||
| 68 | + } | ||
| 61 | 69 | return 0; | |
| 62 | 70 | } | |
| 63 | 71 | ||
@@ -698,6 +706,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args) | |||
| 698 | 706 | && _PyImport_ReleaseLock() < 0 && !PyErr_Occurred()) { | |
| 699 | 707 | PyErr_SetString(PyExc_RuntimeError, | |
| 700 | 708 | "not holding the import lock"); | |
| 709 | + pid = -1; | ||
| 701 | 710 | } | |
| 702 | 711 | import_lock_held = 0; | |
| 703 | 712 | #endif | |
@@ -710,9 +719,8 @@ subprocess_fork_exec(PyObject* self, PyObject *args) | |||
| 710 | 719 | _Py_FreeCharPArray(exec_array); | |
| 711 | 720 | ||
| 712 | 721 | /* Reenable gc in the parent process (or if fork failed). */ | |
| 713 | - if (need_to_reenable_gc && _enable_gc(gc_module)) { | ||
| 714 | - Py_XDECREF(gc_module); | ||
| 715 | - return NULL; | ||
| 722 | + if (_enable_gc(need_to_reenable_gc, gc_module)) { | ||
| 723 | + pid = -1; | ||
| 716 | 724 | } | |
| 717 | 725 | Py_XDECREF(preexec_fn_args_tuple); | |
| 718 | 726 | Py_XDECREF(gc_module); | |
@@ -736,14 +744,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args) | |||
| 736 | 744 | Py_XDECREF(converted_args); | |
| 737 | 745 | Py_XDECREF(fast_args); | |
| 738 | 746 | Py_XDECREF(preexec_fn_args_tuple); | |
| 739 | - | ||
| 740 | - /* Reenable gc if it was disabled. */ | ||
| 741 | - if (need_to_reenable_gc) { | ||
| 742 | - PyObject *exctype, *val, *tb; | ||
| 743 | - PyErr_Fetch(&exctype, &val, &tb); | ||
| 744 | - _enable_gc(gc_module); | ||
| 745 | - PyErr_Restore(exctype, val, tb); | ||
| 746 | - } | ||
| 747 | + _enable_gc(need_to_reenable_gc, gc_module); | ||
| 747 | 748 | Py_XDECREF(gc_module); | |
| 748 | 749 | return NULL; | |
| 749 | 750 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments