https://github.com/python/cpython/commit/eff805b7a7a9678639bbcebe804864406cc4eab2
commit: eff805b7a7a9678639bbcebe804864406cc4eab2
branch: main
author: AN Long <[email protected]>
committer: pablogsal <[email protected]>
date: 2026-06-17T14:09:51-04:00
summary:
gh-151510: Fix __lazy_import__ without frame (#151511)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst
M Lib/test/test_lazy_import/__init__.py
M Modules/_testcapi/import.c
M Python/bltinmodule.c
diff --git a/Lib/test/test_lazy_import/__init__.py
b/Lib/test/test_lazy_import/__init__.py
index 1724beb8ce69517..1c5ab4ef73da2fb 100644
--- a/Lib/test/test_lazy_import/__init__.py
+++ b/Lib/test/test_lazy_import/__init__.py
@@ -1949,6 +1949,17 @@ def filter(*args):
def test_set_bad_filter(self):
self.assertRaises(ValueError, _testcapi.PyImport_SetLazyImportsFilter,
42)
+ def test_dunder_lazy_import_without_frame(self):
+ # gh-151510: __lazy_import__() called with no globals and no running
+ # Python frame must raise TypeError instead of crashing.
+ with self.assertRaisesRegex(
+ TypeError,
+ r"__lazy_import__\(\) missing globals when called without a frame",
+ ):
+ _testcapi.lazy_import_without_frame(
+ "test.test_lazy_import.data.basic2"
+ )
+
if __name__ == '__main__':
unittest.main()
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst
new file mode 100644
index 000000000000000..cfa5ee8d3839c1b
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst
@@ -0,0 +1,2 @@
+Fix a crash in :func:`!__lazy_import__` when called without an explicit
+``globals`` argument and without a current Python frame.
diff --git a/Modules/_testcapi/import.c b/Modules/_testcapi/import.c
index 384a8f52da4b984..11d0e6acaebe1f2 100644
--- a/Modules/_testcapi/import.c
+++ b/Modules/_testcapi/import.c
@@ -1,6 +1,27 @@
#include "parts.h"
#include "util.h"
+static PyObject *
+pyimport_lazyimportwithoutframe(PyObject *self, PyObject *name)
+{
+ PyObject *lazy_import = PyImport_ImportModuleAttrString("builtins",
+ "__lazy_import__");
+ if (lazy_import == NULL) {
+ return NULL;
+ }
+
+ // Simulate being called with no running Python frame (e.g. from a freshly
+ // attached C thread), so that PyEval_GetGlobals() returns NULL.
+ PyThreadState *tstate = PyThreadState_Get();
+ struct _PyInterpreterFrame *saved = tstate->current_frame;
+ tstate->current_frame = NULL;
+ PyObject *res = PyObject_CallOneArg(lazy_import, name);
+ tstate->current_frame = saved;
+
+ Py_DECREF(lazy_import);
+ return res;
+}
+
// Test PyImport_ImportModuleAttr()
static PyObject *
pyimport_importmoduleattr(PyObject *self, PyObject *args)
@@ -95,6 +116,7 @@ static PyMethodDef test_methods[] = {
{"PyImport_GetLazyImportsMode", pyimport_getlazyimportsmode, METH_NOARGS},
{"PyImport_SetLazyImportsFilter", pyimport_setlazyimportsfilter,
METH_VARARGS},
{"PyImport_GetLazyImportsFilter", pyimport_getlazyimportsfilter,
METH_NOARGS},
+ {"lazy_import_without_frame", pyimport_lazyimportwithoutframe, METH_O},
{NULL},
};
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index d5129bf6a5a6bc0..fa64255be00e75d 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -313,6 +313,12 @@ builtin___lazy_import___impl(PyObject *module, PyObject
*name,
PyThreadState *tstate = PyThreadState_GET();
if (globals == NULL) {
globals = PyEval_GetGlobals();
+ if (globals == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "__lazy_import__() missing globals "
+ "when called without a frame");
+ return NULL;
+ }
}
if (locals == NULL) {
locals = globals;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]