[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