diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 0045057f181e1c..f93d088ea758a9 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -956,3 +956,43 @@ class NewStyle[T]: for case in cases: with self.subTest(case=case): weakref.ref(case) + + +class TypeParamsRuntimeTest(unittest.TestCase): + def test_name_error(self): + # gh-109118: This crashed the interpreter due to a refcounting bug + code = """ + class name_2[name_5]: + class name_4[name_5](name_0): + pass + """ + with self.assertRaises(NameError): + run_code(code) + + # Crashed with a slightly different stack trace + code = """ + class name_2[name_5]: + class name_4[name_5: name_5](name_0): + pass + """ + with self.assertRaises(NameError): + run_code(code) + + def test_broken_class_namespace(self): + code = """ + class WeirdMapping(dict): + def __missing__(self, key): + if key == "T": + raise RuntimeError + raise KeyError(key) + + class Meta(type): + def __prepare__(name, bases): + return WeirdMapping() + + class MyClass[V](metaclass=Meta): + class Inner[U](T): + pass + """ + with self.assertRaises(RuntimeError): + run_code(code) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst new file mode 100644 index 00000000000000..f14fce4423896f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst @@ -0,0 +1,2 @@ +Fix interpreter crash when a NameError is raised inside the type parameters +of a generic class. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8820b52774671b..59012d78076795 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1301,10 +1301,8 @@ dummy_func( op(_LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { - Py_DECREF(mod_or_class_dict); goto error; } - Py_DECREF(mod_or_class_dict); if (v == NULL) { v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { @@ -1325,6 +1323,7 @@ dummy_func( } } } + Py_DECREF(mod_or_class_dict); } macro(LOAD_NAME) = _LOAD_LOCALS + _LOAD_FROM_DICT_OR_GLOBALS; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index f4c526a5a8c0a2..5b3d1616950837 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1066,10 +1066,8 @@ mod_or_class_dict = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { - Py_DECREF(mod_or_class_dict); goto error; } - Py_DECREF(mod_or_class_dict); if (v == NULL) { v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { @@ -1090,6 +1088,7 @@ } } } + Py_DECREF(mod_or_class_dict); stack_pointer[-1] = v; break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 84f83db128ea50..5e07f61192f0a1 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1694,10 +1694,8 @@ { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { - Py_DECREF(mod_or_class_dict); goto error; } - Py_DECREF(mod_or_class_dict); if (v == NULL) { v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { @@ -1718,6 +1716,7 @@ } } } + Py_DECREF(mod_or_class_dict); } STACK_GROW(1); stack_pointer[-1] = v; @@ -1730,10 +1729,8 @@ mod_or_class_dict = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { - Py_DECREF(mod_or_class_dict); goto error; } - Py_DECREF(mod_or_class_dict); if (v == NULL) { v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { @@ -1754,6 +1751,7 @@ } } } + Py_DECREF(mod_or_class_dict); stack_pointer[-1] = v; DISPATCH(); }