[Python-checkins] cpython (merge 3.5 -> default): Issue #25764: Merge subprocess fix from 3.5
martin.panter
python-checkins at python.org
Fri Dec 4 21:35:35 EST 2015
https://hg.python.org/cpython/rev/b10c58a740b9
changeset: 99438:b10c58a740b9
parent: 99435:1b1900d2a537
parent: 99437:ae27ad306dbf
user: Martin Panter <vadmium+py at gmail.com>
date: Sat Dec 05 02:27:58 2015 +0000
summary:
Issue #25764: Merge subprocess fix from 3.5
files:
Lib/test/test_subprocess.py | 16 +++++++++++
Misc/NEWS | 3 ++
Modules/_posixsubprocess.c | 35 ++++++++++++------------
3 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -1512,6 +1512,22 @@
if not enabled:
gc.disable()
+ def test_preexec_fork_failure(self):
+ # The internal code did not preserve the previous exception when
+ # re-enabling garbage collection
+ try:
+ from resource import getrlimit, setrlimit, RLIMIT_NPROC
+ except ImportError as err:
+ self.skipTest(err) # RLIMIT_NPROC is specific to Linux and BSD
+ limits = getrlimit(RLIMIT_NPROC)
+ [_, hard] = limits
+ setrlimit(RLIMIT_NPROC, (0, hard))
+ self.addCleanup(setrlimit, RLIMIT_NPROC, limits)
+ # Forking should raise EAGAIN, translated to BlockingIOError
+ with self.assertRaises(BlockingIOError):
+ subprocess.call([sys.executable, '-c', ''],
+ preexec_fn=lambda: None)
+
def test_args_string(self):
# args is a string
fd, fname = tempfile.mkstemp()
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -109,6 +109,9 @@
Library
-------
+- Issue #25764: In the subprocess module, preserve any exception caused by
+ fork() failure when preexec_fn is used.
+
- Issue #25771: Tweak the exception message for importlib.util.resolve_name()
when 'package' isn't specified but necessary.
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
--- a/Modules/_posixsubprocess.c
+++ b/Modules/_posixsubprocess.c
@@ -47,17 +47,25 @@
#define POSIX_CALL(call) do { if ((call) == -1) goto error; } while (0)
-/* Given the gc module call gc.enable() and return 0 on success. */
+/* If gc was disabled, call gc.enable(). Return 0 on success. */
static int
-_enable_gc(PyObject *gc_module)
+_enable_gc(int need_to_reenable_gc, PyObject *gc_module)
{
PyObject *result;
_Py_IDENTIFIER(enable);
+ PyObject *exctype, *val, *tb;
- result = _PyObject_CallMethodId(gc_module, &PyId_enable, NULL);
- if (result == NULL)
- return 1;
- Py_DECREF(result);
+ if (need_to_reenable_gc) {
+ PyErr_Fetch(&exctype, &val, &tb);
+ result = _PyObject_CallMethodId(gc_module, &PyId_enable, NULL);
+ if (exctype != NULL) {
+ PyErr_Restore(exctype, val, tb);
+ }
+ if (result == NULL) {
+ return 1;
+ }
+ Py_DECREF(result);
+ }
return 0;
}
@@ -698,6 +706,7 @@
&& _PyImport_ReleaseLock() < 0 && !PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError,
"not holding the import lock");
+ pid = -1;
}
import_lock_held = 0;
#endif
@@ -710,9 +719,8 @@
_Py_FreeCharPArray(exec_array);
/* Reenable gc in the parent process (or if fork failed). */
- if (need_to_reenable_gc && _enable_gc(gc_module)) {
- Py_XDECREF(gc_module);
- return NULL;
+ if (_enable_gc(need_to_reenable_gc, gc_module)) {
+ pid = -1;
}
Py_XDECREF(preexec_fn_args_tuple);
Py_XDECREF(gc_module);
@@ -736,14 +744,7 @@
Py_XDECREF(converted_args);
Py_XDECREF(fast_args);
Py_XDECREF(preexec_fn_args_tuple);
-
- /* Reenable gc if it was disabled. */
- if (need_to_reenable_gc) {
- PyObject *exctype, *val, *tb;
- PyErr_Fetch(&exctype, &val, &tb);
- _enable_gc(gc_module);
- PyErr_Restore(exctype, val, tb);
- }
+ _enable_gc(need_to_reenable_gc, gc_module);
Py_XDECREF(gc_module);
return NULL;
}
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list