summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Python/import.c
diff options
context:
space:
mode:
authorshadchin <[email protected]>2026-05-07 07:27:37 +0300
committershadchin <[email protected]>2026-05-07 07:57:26 +0300
commitcdd663c58847eced4c810b05edda251c70a10438 (patch)
tree268b4bf9860a9c77564d93a803d7ecfedd3586cd /contrib/tools/python3/Python/import.c
parentb6f47db70a8a8e904e3f38bed557097ff00f0b3b (diff)
Update Python 3 to 3.13.13
commit_hash:526db1f6570443324e2690db042314848cd47d2e
Diffstat (limited to 'contrib/tools/python3/Python/import.c')
-rw-r--r--contrib/tools/python3/Python/import.c60
1 files changed, 58 insertions, 2 deletions
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);