Skip to content

Commit 3d5d090

Browse files
author
Andres
committed
gh-145076: Validate type inputs in __lazy_import__
1 parent fbd3b25 commit 3d5d090

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

Lib/test/test_import/test_lazy_imports.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,21 @@ def test_dunder_lazy_import_builtins(self):
409409
self.assertNotIn("test.test_import.data.lazy_imports.basic2", sys.modules)
410410
self.assertEqual(dunder_lazy_import_builtins.basic.basic2, 42)
411411

412+
def test_dunder_lazy_import_argument_validation(self):
413+
"""__lazy_import__ should strictly validate argument types to avoid SystemError."""
414+
invalid_type_scenarios = [
415+
(123, {}, {}, [], 0, "argument 1 must be str"),
416+
('os', 1, {}, [], 0, "argument 2 must be dict"),
417+
('os', {}, "not_a_dict", [], 0, "argument 3 must be dict"),
418+
('os', {}, {}, 42, 0, "argument 4 must be a list or tuple"),
419+
('os', {}, {}, "string_instead_of_list", 0, "argument 4 must be a list or tuple"),
420+
]
421+
422+
for name, glbs, lcls, flist, lvl, msg in invalid_type_scenarios:
423+
with self.subTest(case=msg):
424+
with self.assertRaisesRegex(TypeError, msg):
425+
__lazy_import__(name, glbs, lcls, flist, lvl)
426+
412427

413428
class SysLazyImportsAPITests(unittest.TestCase):
414429
"""Tests for sys lazy imports API functions."""
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed a :exc:`SystemError` in :func:`__lazy_import__` caused by passing
2+
invalid argument types. Added proper type validation for *name*, *globals*,
3+
*locals*, and *fromlist* arguments.

Python/bltinmodule.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,37 @@ builtin___lazy_import___impl(PyObject *module, PyObject *name,
311311
{
312312
PyObject *builtins;
313313
PyThreadState *tstate = PyThreadState_GET();
314+
315+
// Validate input arguments
316+
if (!PyUnicode_Check(name)) {
317+
PyErr_Format(PyExc_TypeError,
318+
"__lazy_import__() argument 1 must be str, not %.200s",
319+
Py_TYPE(name)->tp_name);
320+
return NULL;
321+
}
322+
323+
if (globals != NULL && !PyDict_Check(globals)) {
324+
PyErr_Format(PyExc_TypeError,
325+
"__lazy_import__() argument 2 must be dict, not %.200s",
326+
Py_TYPE(globals)->tp_name);
327+
return NULL;
328+
}
329+
330+
if (locals != NULL && !PyDict_Check(locals)) {
331+
PyErr_Format(PyExc_TypeError,
332+
"__lazy_import__() argument 3 must be dict, not %.200s",
333+
Py_TYPE(locals)->tp_name);
334+
return NULL;
335+
}
336+
337+
if (fromlist != NULL && fromlist != Py_None &&
338+
!PyList_Check(fromlist) && !PyTuple_Check(fromlist)) {
339+
PyErr_Format(PyExc_TypeError,
340+
"__lazy_import__() argument 4 must be a list or tuple, not %.200s",
341+
Py_TYPE(fromlist)->tp_name);
342+
return NULL;
343+
}
344+
314345
if (globals == NULL) {
315346
globals = PyEval_GetGlobals();
316347
}

0 commit comments

Comments
 (0)