From 135abecf5b5f3c25a35c19182e41600a7fee2457 Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Sun, 10 May 2026 11:03:15 +0800 Subject: [PATCH] Fix interpreter lifecycle cleanup paths Fix multiple resource-management and error-path bugs in the interpreter lifecycle. Release the builtins module reference on builtin initialization failures and keep it owned until default import initialization succeeds, avoiding an extra NULL assignment. Also DECREF results from non-dict sys.modules clear calls, route subinterpreter initialization failures through cleanup after thread-state detach, release __main__ setup references on PyDict_SetItemString failures, and check stdin/stdout sys object setup failures consistently with stderr. Tests run: - ./configure --with-pydebug - git diff --check - make -j2 Python/pylifecycle.o - make -j2 python Programs/_testembed - make -j2 - Programs/_testembed test_repeated_init_and_subinterpreters - ./python - <<'PY' import _interpreters interp = _interpreters.create() _interpreters.destroy(interp) print('ok') PY - make patchcheck (fails because this checkout has no upstream remote matching https://github.com/python/cpython) --- Python/pylifecycle.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 46579a45f4cc39..49041453f040bd 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -909,10 +909,12 @@ pycore_init_builtins(PyThreadState *tstate) interp->callable_cache.object__getattribute__ = object__getattribute__; if (_PyType_InitSlotDefs(interp) < 0) { + Py_DECREF(bimod); return _PyStatus_ERR("failed to init slotdefs"); } if (_PyBuiltins_AddExceptions(bimod) < 0) { + Py_DECREF(bimod); return _PyStatus_ERR("failed to add exceptions to builtins"); } @@ -920,12 +922,12 @@ pycore_init_builtins(PyThreadState *tstate) if (interp->builtins_copy == NULL) { goto error; } - Py_DECREF(bimod); if (_PyImport_InitDefaultImportFunc(interp) < 0) { goto error; } + Py_DECREF(bimod); assert(!_PyErr_Occurred(tstate)); return _PyStatus_OK(); @@ -1823,9 +1825,13 @@ finalize_clear_modules_dict(PyObject *modules) PyDict_Clear(modules); } else { - if (PyObject_CallMethodNoArgs(modules, &_Py_ID(clear)) == NULL) { + PyObject *result = PyObject_CallMethodNoArgs(modules, &_Py_ID(clear)); + if (result == NULL) { PyErr_FormatUnraisable("Exception ignored while clearing sys.modules"); } + else { + Py_DECREF(result); + } } } @@ -2702,14 +2708,14 @@ new_interpreter(PyThreadState **tstate_p, // didn't depend on interp->feature_flags being set already. status = _PyObject_InitState(interp); if (_PyStatus_EXCEPTION(status)) { - return status; + goto error; } #ifdef Py_STATS // initialize pystats. This must be done after the settings are loaded. status = _PyStats_InterpInit(interp); if (_PyStatus_EXCEPTION(status)) { - return status; + goto error; } #endif @@ -2929,6 +2935,7 @@ add_main_module(PyInterpreterState *interp) return _PyStatus_ERR("Failed to retrieve builtins module"); } if (PyDict_SetItemString(d, "__builtins__", bimod) < 0) { + Py_DECREF(bimod); return _PyStatus_ERR("Failed to initialize __main__.__builtins__"); } Py_DECREF(bimod); @@ -2952,6 +2959,7 @@ add_main_module(PyInterpreterState *interp) return _PyStatus_ERR("Failed to retrieve BuiltinImporter"); } if (PyDict_SetItemString(d, "__loader__", loader) < 0) { + Py_DECREF(loader); return _PyStatus_ERR("Failed to initialize __main__.__loader__"); } Py_DECREF(loader); @@ -3186,8 +3194,14 @@ init_sys_streams(PyThreadState *tstate) config->stdio_errors); if (std == NULL) goto error; - PySys_SetObject("__stdin__", std); - _PySys_SetAttr(&_Py_ID(stdin), std); + if (PySys_SetObject("__stdin__", std) < 0) { + Py_DECREF(std); + goto error; + } + if (_PySys_SetAttr(&_Py_ID(stdin), std) < 0) { + Py_DECREF(std); + goto error; + } Py_DECREF(std); /* Set sys.stdout */ @@ -3197,8 +3211,14 @@ init_sys_streams(PyThreadState *tstate) config->stdio_errors); if (std == NULL) goto error; - PySys_SetObject("__stdout__", std); - _PySys_SetAttr(&_Py_ID(stdout), std); + if (PySys_SetObject("__stdout__", std) < 0) { + Py_DECREF(std); + goto error; + } + if (_PySys_SetAttr(&_Py_ID(stdout), std) < 0) { + Py_DECREF(std); + goto error; + } Py_DECREF(std); #if 1 /* Disable this if you have trouble debugging bootstrap stuff */