Skip to content

Commit 3c448e8

Browse files
committed
gh-109118: Fix runtime crash when NameError happens in PEP 695 function
1 parent b9831e5 commit 3c448e8

File tree

5 files changed

+46
-8
lines changed

5 files changed

+46
-8
lines changed

Lib/test/test_type_params.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,3 +956,43 @@ class NewStyle[T]:
956956
for case in cases:
957957
with self.subTest(case=case):
958958
weakref.ref(case)
959+
960+
961+
class TypeParamsRuntimeTest(unittest.TestCase):
962+
def test_name_error(self):
963+
# gh-109118: This crashed the interpreter due to a refcounting bug
964+
code = """
965+
class name_2[name_5]:
966+
class name_4[name_5](name_0):
967+
pass
968+
"""
969+
with self.assertRaises(NameError):
970+
run_code(code)
971+
972+
# Crashed with a slightly different stack trace
973+
code = """
974+
class name_2[name_5]:
975+
class name_4[name_5: name_5](name_0):
976+
pass
977+
"""
978+
with self.assertRaises(NameError):
979+
run_code(code)
980+
981+
def test_broken_class_namespace(self):
982+
code = """
983+
class WeirdMapping(dict):
984+
def __missing__(self, key):
985+
if key == "T":
986+
raise RuntimeError
987+
raise KeyError(key)
988+
989+
class Meta(type):
990+
def __prepare__(name, bases):
991+
return WeirdMapping()
992+
993+
class MyClass[V](metaclass=Meta):
994+
class Inner[U](T):
995+
pass
996+
"""
997+
with self.assertRaises(RuntimeError):
998+
run_code(code)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix interpreter crash when a NameError is raised inside the type parameters
2+
of a generic class.

Python/bytecodes.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,10 +1301,8 @@ dummy_func(
13011301
op(_LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) {
13021302
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
13031303
if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) {
1304-
Py_DECREF(mod_or_class_dict);
13051304
goto error;
13061305
}
1307-
Py_DECREF(mod_or_class_dict);
13081306
if (v == NULL) {
13091307
v = PyDict_GetItemWithError(GLOBALS(), name);
13101308
if (v != NULL) {
@@ -1325,6 +1323,7 @@ dummy_func(
13251323
}
13261324
}
13271325
}
1326+
Py_DECREF(mod_or_class_dict);
13281327
}
13291328

13301329
macro(LOAD_NAME) = _LOAD_LOCALS + _LOAD_FROM_DICT_OR_GLOBALS;

Python/executor_cases.c.h

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)