From d06113c7a7cac76a28847702685e601b79f71bf8 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Fri, 19 Sep 2025 10:41:09 -0400 Subject: [PATCH] gh-112729: Correctly fail when the process is out of memory during interpreter creation (GH-139164) --- Lib/test/test_interpreters/test_stress.py | 9 +++++++++ ...2025-09-19-09-36-42.gh-issue-112729.mmty0_.rst | 2 ++ Python/pylifecycle.c | 15 +++++++-------- 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-09-19-09-36-42.gh-issue-112729.mmty0_.rst diff --git a/Lib/test/test_interpreters/test_stress.py b/Lib/test/test_interpreters/test_stress.py index e25e67a0d4f4..6b40a536bd3c 100644 --- a/Lib/test/test_interpreters/test_stress.py +++ b/Lib/test/test_interpreters/test_stress.py @@ -7,6 +7,7 @@ from test.support import threading_helper # Raise SkipTest if subinterpreters not supported. import_helper.import_module('_interpreters') from concurrent import interpreters +from concurrent.interpreters import InterpreterError from .utils import TestBase @@ -74,6 +75,14 @@ class StressTests(TestBase): start.set() support.gc_collect() + def test_create_interpreter_no_memory(self): + import _interpreters + _testcapi = import_helper.import_module("_testcapi") + + with self.assertRaises(InterpreterError): + _testcapi.set_nomemory(0, 1) + _interpreters.create() + if __name__ == '__main__': # Test needs to be a package, so we can do relative imports. diff --git a/Misc/NEWS.d/next/Library/2025-09-19-09-36-42.gh-issue-112729.mmty0_.rst b/Misc/NEWS.d/next/Library/2025-09-19-09-36-42.gh-issue-112729.mmty0_.rst new file mode 100644 index 000000000000..950853a696f3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-19-09-36-42.gh-issue-112729.mmty0_.rst @@ -0,0 +1,2 @@ +Fix crash when calling :func:`concurrent.interpreters.create` when the +process is out of memory. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 372318897406..37af58a68d78 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2411,18 +2411,17 @@ new_interpreter(PyThreadState **tstate_p, interpreters: disable PyGILState_Check(). */ runtime->gilstate.check_enabled = 0; - PyInterpreterState *interp = PyInterpreterState_New(); + // XXX Might new_interpreter() have been called without the GIL held? + PyThreadState *save_tstate = _PyThreadState_GET(); + PyThreadState *tstate = NULL; + PyInterpreterState *interp; + status = _PyInterpreterState_New(save_tstate, &interp); if (interp == NULL) { - *tstate_p = NULL; - return _PyStatus_OK(); + goto error; } _PyInterpreterState_SetWhence(interp, whence); interp->_ready = 1; - // XXX Might new_interpreter() have been called without the GIL held? - PyThreadState *save_tstate = _PyThreadState_GET(); - PyThreadState *tstate = NULL; - /* From this point until the init_interp_create_gil() call, we must not do anything that requires that the GIL be held (or otherwise exist). That applies whether or not the new @@ -2498,7 +2497,7 @@ error: *tstate_p = NULL; if (tstate != NULL) { Py_EndInterpreter(tstate); - } else { + } else if (interp != NULL) { PyInterpreterState_Delete(interp); } if (save_tstate != NULL) { -- 2.47.3