diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index fbb64332f58..ddbe7409604 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -57,6 +57,7 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate, PyObject *name, PyO #define IMPORTS_INIT \ { \ DLOPENFLAGS_INIT \ + .lazy_import_resolution_depth = 0, \ .find_and_load = { \ .header = 1, \ }, \ diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index 6cc48dd901a..7b232157da1 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -316,6 +316,8 @@ struct _import_state { PyObject *lazy_import_func; int lazy_imports_mode; PyObject *lazy_imports_filter; + /* Counter to prevent recursive lazy import creation */ + int lazy_import_resolution_depth; /* The global import lock. */ _PyRecursiveMutex lock; /* diagnostic info in PyImport_ImportModuleLevelObject() */ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index ea28853e1de..b30c295580e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1835,7 +1835,7 @@ dummy_func( PyObject *res_o = PyStackRef_AsPyObjectBorrow(*res); if (PyLazyImport_CheckExact(res_o)) { PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, res_o); - if (PyDict_SetItem(GLOBALS(), name, l_v) < 0) { + if (l_v != NULL && PyDict_SetItem(GLOBALS(), name, l_v) < 0) { JUMP_TO_LABEL(error); } res_o = l_v; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index ae48e8e41c1..e352dc4e43c 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2491,7 +2491,7 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, res_o); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyDict_SetItem(GLOBALS(), name, l_v) < 0) { + if (l_v != NULL && PyDict_SetItem(GLOBALS(), name, l_v) < 0) { JUMP_TO_LABEL(error); } res_o = l_v; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 509a56647ae..e7bffae1647 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -9194,7 +9194,7 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *l_v = _PyImport_LoadLazyImportTstate(tstate, res_o); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyDict_SetItem(GLOBALS(), name, l_v) < 0) { + if (l_v != NULL && PyDict_SetItem(GLOBALS(), name, l_v) < 0) { JUMP_TO_LABEL(error); } res_o = l_v; diff --git a/Python/import.c b/Python/import.c index 551618fe44c..0ccccbbbda7 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3738,6 +3738,10 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import) PyObject *globals = PyEval_GetGlobals(); + // Increment counter to prevent recursive lazy import creation + PyInterpreterState *interp = tstate->interp; + interp->imports.lazy_import_resolution_depth++; + if (full) { obj = _PyEval_ImportNameWithImport(tstate, lz->lz_import_func, @@ -3749,6 +3753,7 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import) } else { PyObject *name = PyUnicode_Substring(lz->lz_from, 0, dot); if (name == NULL) { + interp->imports.lazy_import_resolution_depth--; goto error; } obj = _PyEval_ImportNameWithImport(tstate, @@ -3761,6 +3766,9 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import) Py_DECREF(name); } + // Decrement counter + interp->imports.lazy_import_resolution_depth--; + if (obj == NULL) { goto error; } @@ -3942,7 +3950,8 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, goto error; } - if (globals != NULL && + // Only check __lazy_modules__ if we're not already resolving a lazy import + if (interp->imports.lazy_import_resolution_depth == 0 && globals != NULL && PyMapping_GetOptionalItem(globals, &_Py_ID(__lazy_modules__), &lazy_modules) < 0) { goto error; } @@ -3965,7 +3974,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, goto error; } - if (lazy_modules != NULL) { + if (interp->imports.lazy_import_resolution_depth == 0 && lazy_modules != NULL) { // Check and see if the module is opting in w/o syntax for backwards compatibility // with older Python versions. int contains = PySequence_Contains(lazy_modules, name); @@ -3988,7 +3997,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, return NULL; } - final_mod = _PyImport_LazyImportModuleLevelObject(tstate, name, import_func, globals, + final_mod = _PyImport_LazyImportModuleLevelObject(tstate, name, import_func, globals, locals, fromlist, level); Py_DECREF(import_func); goto error;