Skip to content

Commit acde502

Browse files
[3.12] gh-109118: Fix runtime crash when NameError happens in PEP 695 function (GH-109123) (#109173)
* gh-109118: Fix runtime crash when NameError happens in PEP 695 function (#109123) (cherry picked from commit 17f9941) * [3.12] gh-109118: Fix runtime crash when NameError happens in PEP 695 function (GH-109123). (cherry picked from commit 17f9941) Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent c76f4b9 commit acde502

File tree

5 files changed

+501
-430
lines changed

5 files changed

+501
-430
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: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,7 @@ dummy_func(
11651165
}
11661166
}
11671167

1168-
op(_LOAD_LOCALS, ( -- locals)) {
1168+
inst(LOAD_LOCALS, ( -- locals)) {
11691169
locals = LOCALS();
11701170
if (locals == NULL) {
11711171
_PyErr_SetString(tstate, PyExc_SystemError,
@@ -1175,31 +1175,26 @@ dummy_func(
11751175
Py_INCREF(locals);
11761176
}
11771177

1178-
macro(LOAD_LOCALS) = _LOAD_LOCALS;
1179-
1180-
op(_LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) {
1178+
inst(LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) {
11811179
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
11821180
if (PyDict_CheckExact(mod_or_class_dict)) {
11831181
v = PyDict_GetItemWithError(mod_or_class_dict, name);
11841182
if (v != NULL) {
11851183
Py_INCREF(v);
11861184
}
11871185
else if (_PyErr_Occurred(tstate)) {
1188-
Py_DECREF(mod_or_class_dict);
11891186
goto error;
11901187
}
11911188
}
11921189
else {
11931190
v = PyObject_GetItem(mod_or_class_dict, name);
11941191
if (v == NULL) {
11951192
if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
1196-
Py_DECREF(mod_or_class_dict);
11971193
goto error;
11981194
}
11991195
_PyErr_Clear(tstate);
12001196
}
12011197
}
1202-
Py_DECREF(mod_or_class_dict);
12031198
if (v == NULL) {
12041199
v = PyDict_GetItemWithError(GLOBALS(), name);
12051200
if (v != NULL) {
@@ -1234,11 +1229,70 @@ dummy_func(
12341229
}
12351230
}
12361231
}
1232+
DECREF_INPUTS();
12371233
}
12381234

1239-
macro(LOAD_NAME) = _LOAD_LOCALS + _LOAD_FROM_DICT_OR_GLOBALS;
1240-
1241-
macro(LOAD_FROM_DICT_OR_GLOBALS) = _LOAD_FROM_DICT_OR_GLOBALS;
1235+
inst(LOAD_NAME, (-- v)) {
1236+
PyObject *mod_or_class_dict = LOCALS();
1237+
if (mod_or_class_dict == NULL) {
1238+
_PyErr_SetString(tstate, PyExc_SystemError,
1239+
"no locals found");
1240+
ERROR_IF(true, error);
1241+
}
1242+
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
1243+
if (PyDict_CheckExact(mod_or_class_dict)) {
1244+
v = PyDict_GetItemWithError(mod_or_class_dict, name);
1245+
if (v != NULL) {
1246+
Py_INCREF(v);
1247+
}
1248+
else if (_PyErr_Occurred(tstate)) {
1249+
goto error;
1250+
}
1251+
}
1252+
else {
1253+
v = PyObject_GetItem(mod_or_class_dict, name);
1254+
if (v == NULL) {
1255+
if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
1256+
goto error;
1257+
}
1258+
_PyErr_Clear(tstate);
1259+
}
1260+
}
1261+
if (v == NULL) {
1262+
v = PyDict_GetItemWithError(GLOBALS(), name);
1263+
if (v != NULL) {
1264+
Py_INCREF(v);
1265+
}
1266+
else if (_PyErr_Occurred(tstate)) {
1267+
goto error;
1268+
}
1269+
else {
1270+
if (PyDict_CheckExact(BUILTINS())) {
1271+
v = PyDict_GetItemWithError(BUILTINS(), name);
1272+
if (v == NULL) {
1273+
if (!_PyErr_Occurred(tstate)) {
1274+
format_exc_check_arg(
1275+
tstate, PyExc_NameError,
1276+
NAME_ERROR_MSG, name);
1277+
}
1278+
goto error;
1279+
}
1280+
Py_INCREF(v);
1281+
}
1282+
else {
1283+
v = PyObject_GetItem(BUILTINS(), name);
1284+
if (v == NULL) {
1285+
if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
1286+
format_exc_check_arg(
1287+
tstate, PyExc_NameError,
1288+
NAME_ERROR_MSG, name);
1289+
}
1290+
goto error;
1291+
}
1292+
}
1293+
}
1294+
}
1295+
}
12421296

12431297
family(load_global, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = {
12441298
LOAD_GLOBAL,

0 commit comments

Comments
 (0)