]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-151510: Fix __lazy_import__ without frame (#151511) main
authorAN Long <aisk@users.noreply.github.com>
Wed, 17 Jun 2026 18:09:51 +0000 (03:09 +0900)
committerGitHub <noreply@github.com>
Wed, 17 Jun 2026 18:09:51 +0000 (14:09 -0400)
Lib/test/test_lazy_import/__init__.py
Misc/NEWS.d/next/Core_and_Builtins/2026-06-16-00-45-42.gh-issue-151510.HJ-kGn.rst [new file with mode: 0644]
Modules/_testcapi/import.c
Python/bltinmodule.c

index 1724beb8ce695170e1d9df23a9fe348143bd5558..1c5ab4ef73da2fb739fa1c62202ddb53f640be02 100644 (file)
@@ -1949,6 +1949,17 @@ class LazyCApiTests(LazyImportTestCase):
     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 (file)
index 0000000..cfa5ee8
--- /dev/null
@@ -0,0 +1,2 @@
+Fix a crash in :func:`!__lazy_import__` when called without an explicit
+``globals`` argument and without a current Python frame.
index 384a8f52da4b98423b0535207b34007ce14eafb4..11d0e6acaebe1f21e0bf1c651ed96b71cad2be8e 100644 (file)
@@ -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},
 };
 
index d5129bf6a5a6bc007380848e8c367d07a2731b89..fa64255be00e75db7f0ebfb34afb88ad46f70235 100644 (file)
@@ -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;