Issue #25764: Preserve subprocess fork exception when preexec_fn used
Also fix handling of failure to release the import lock.
This commit is contained in:
parent
c7217d7c22
commit
afdd51343c
|
@ -1416,6 +1416,22 @@ class POSIXProcessTestCase(BaseTestCase):
|
||||||
if not enabled:
|
if not enabled:
|
||||||
gc.disable()
|
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):
|
def test_args_string(self):
|
||||||
# args is a string
|
# args is a string
|
||||||
fd, fname = tempfile.mkstemp()
|
fd, fname = tempfile.mkstemp()
|
||||||
|
|
|
@ -115,6 +115,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #25764: In the subprocess module, preserve any exception caused by
|
||||||
|
fork() failure when preexec_fn is used.
|
||||||
|
|
||||||
- Issue #6478: _strptime's regexp cache now is reset after changing timezone
|
- Issue #6478: _strptime's regexp cache now is reset after changing timezone
|
||||||
with time.tzset().
|
with time.tzset().
|
||||||
|
|
||||||
|
|
|
@ -47,17 +47,25 @@
|
||||||
#define POSIX_CALL(call) do { if ((call) == -1) goto error; } while (0)
|
#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
|
static int
|
||||||
_enable_gc(PyObject *gc_module)
|
_enable_gc(int need_to_reenable_gc, PyObject *gc_module)
|
||||||
{
|
{
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
_Py_IDENTIFIER(enable);
|
_Py_IDENTIFIER(enable);
|
||||||
|
PyObject *exctype, *val, *tb;
|
||||||
|
|
||||||
result = _PyObject_CallMethodId(gc_module, &PyId_enable, NULL);
|
if (need_to_reenable_gc) {
|
||||||
if (result == NULL)
|
PyErr_Fetch(&exctype, &val, &tb);
|
||||||
return 1;
|
result = _PyObject_CallMethodId(gc_module, &PyId_enable, NULL);
|
||||||
Py_DECREF(result);
|
if (exctype != NULL) {
|
||||||
|
PyErr_Restore(exctype, val, tb);
|
||||||
|
}
|
||||||
|
if (result == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Py_DECREF(result);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,6 +699,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
|
||||||
_PyImport_ReleaseLock() < 0 && !PyErr_Occurred()) {
|
_PyImport_ReleaseLock() < 0 && !PyErr_Occurred()) {
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
"not holding the import lock");
|
"not holding the import lock");
|
||||||
|
pid = -1;
|
||||||
}
|
}
|
||||||
import_lock_held = 0;
|
import_lock_held = 0;
|
||||||
|
|
||||||
|
@ -702,9 +711,8 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
|
||||||
_Py_FreeCharPArray(exec_array);
|
_Py_FreeCharPArray(exec_array);
|
||||||
|
|
||||||
/* Reenable gc in the parent process (or if fork failed). */
|
/* Reenable gc in the parent process (or if fork failed). */
|
||||||
if (need_to_reenable_gc && _enable_gc(gc_module)) {
|
if (_enable_gc(need_to_reenable_gc, gc_module)) {
|
||||||
Py_XDECREF(gc_module);
|
pid = -1;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
Py_XDECREF(preexec_fn_args_tuple);
|
Py_XDECREF(preexec_fn_args_tuple);
|
||||||
Py_XDECREF(gc_module);
|
Py_XDECREF(gc_module);
|
||||||
|
@ -726,14 +734,7 @@ cleanup:
|
||||||
Py_XDECREF(converted_args);
|
Py_XDECREF(converted_args);
|
||||||
Py_XDECREF(fast_args);
|
Py_XDECREF(fast_args);
|
||||||
Py_XDECREF(preexec_fn_args_tuple);
|
Py_XDECREF(preexec_fn_args_tuple);
|
||||||
|
_enable_gc(need_to_reenable_gc, gc_module);
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
Py_XDECREF(gc_module);
|
Py_XDECREF(gc_module);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue