From cdd663c58847eced4c810b05edda251c70a10438 Mon Sep 17 00:00:00 2001 From: shadchin Date: Thu, 7 May 2026 07:27:37 +0300 Subject: Update Python 3 to 3.13.13 commit_hash:526db1f6570443324e2690db042314848cd47d2e --- contrib/tools/python3/Python/import.c | 60 +++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) (limited to 'contrib/tools/python3/Python/import.c') diff --git a/contrib/tools/python3/Python/import.c b/contrib/tools/python3/Python/import.c index 03a49ea0599..456f6c40b54 100644 --- a/contrib/tools/python3/Python/import.c +++ b/contrib/tools/python3/Python/import.c @@ -252,12 +252,32 @@ PyImport_GetModule(PyObject *name) mod = import_get_module(tstate, name); if (mod != NULL && mod != Py_None) { if (import_ensure_initialized(tstate->interp, mod, name) < 0) { + goto error; + } + /* Verify the module is still in sys.modules. Another thread may have + removed it (due to import failure) between our import_get_module() + call and the _initializing check in import_ensure_initialized(). */ + PyObject *mod_check = import_get_module(tstate, name); + if (mod_check != mod) { + Py_XDECREF(mod_check); + if (_PyErr_Occurred(tstate)) { + goto error; + } + /* The module was removed or replaced. Return NULL to report + "not found" rather than trying to keep up with racing + modifications to sys.modules; returning the new value would + require looping to redo the ensure_initialized check. */ Py_DECREF(mod); - remove_importlib_frames(tstate); return NULL; } + Py_DECREF(mod_check); } return mod; + +error: + Py_DECREF(mod); + remove_importlib_frames(tstate); + return NULL; } /* Get the module object corresponding to a module name. @@ -2069,13 +2089,29 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0, } main_finally: + if (rc < 0) { + _Py_ext_module_loader_result_apply_error(&res, name_buf); + } + /* Switch back to the subinterpreter. */ if (switched) { + // gh-144601: The exception object can't be transferred across + // interpreters. Instead, we print out an unraisable exception, and + // then raise a different exception for the calling interpreter. + if (rc < 0) { + assert(PyErr_Occurred()); + PyErr_FormatUnraisable("Exception while importing from subinterpreter"); + } assert(main_tstate != tstate); switch_back_from_main_interpreter(tstate, main_tstate, mod); /* Any module we got from the init function will have to be * reloaded in the subinterpreter. */ mod = NULL; + if (rc < 0) { + PyErr_SetString(PyExc_ImportError, + "failed to import from subinterpreter due to exception"); + goto error; + } } /*****************************************************************/ @@ -2084,7 +2120,6 @@ main_finally: /* Finally we handle the error return from _PyImport_RunModInitFunc(). */ if (rc < 0) { - _Py_ext_module_loader_result_apply_error(&res, name_buf); goto error; } @@ -3789,6 +3824,27 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, if (import_ensure_initialized(tstate->interp, mod, abs_name) < 0) { goto error; } + /* Verify the module is still in sys.modules. Another thread may have + removed it (due to import failure) between our import_get_module() + call and the _initializing check in import_ensure_initialized(). + If removed, we retry the import to preserve normal semantics: the + caller gets the exception from the actual import failure rather + than a synthetic error. */ + PyObject *mod_check = import_get_module(tstate, abs_name); + if (mod_check != mod) { + Py_XDECREF(mod_check); + if (_PyErr_Occurred(tstate)) { + goto error; + } + Py_DECREF(mod); + mod = import_find_and_load(tstate, abs_name); + if (mod == NULL) { + goto error; + } + } + else { + Py_DECREF(mod_check); + } } else { Py_XDECREF(mod); -- cgit v1.3