Skip to content

Commit 1034e07

Browse files
authored
gh-154275: Do not crash on deeply nested __parameters__ in GenericAlias (#154277)
1 parent 63b564f commit 1034e07

3 files changed

Lines changed: 32 additions & 13 deletions

File tree

Lib/test/test_typing.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
from test.support import (
5353
captured_stderr, cpython_only, requires_docstrings, import_helper, run_code,
5454
subTests, EqualToForwardRef,
55+
exceeds_recursion_limit, skip_if_huge_c_stack, skip_wasi_stack_overflow,
56+
skip_emscripten_stack_overflow,
5557
)
5658
from test.typinganndata import (
5759
ann_module695, mod_generics_cache, _typed_dict_helper,
@@ -5094,6 +5096,17 @@ class MM2(collections.abc.MutableMapping, MutableMapping[str, str]):
50945096
pass
50955097
self.assertEqual(MM2.__bases__, (collections.abc.MutableMapping, Generic))
50965098

5099+
@cpython_only
5100+
@skip_if_huge_c_stack()
5101+
@skip_wasi_stack_overflow()
5102+
@skip_emscripten_stack_overflow()
5103+
def test_parameters_deep_recursion(self):
5104+
x = [0]
5105+
for _ in range(exceeds_recursion_limit()):
5106+
x = [x]
5107+
with self.assertRaisesRegex(RecursionError, "in __parameter__ calculation"):
5108+
list[x].__parameters__
5109+
50975110
def test_orig_bases(self):
50985111
T = TypeVar('T')
50995112
class C(typing.Dict[str, T]): ...
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash when getting deeply nested ``__parameters__`` from a
2+
:class:`types.GenericAlias` objects.

Objects/genericaliasobject.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ PyObject *
186186
_Py_make_parameters(PyObject *args)
187187
{
188188
assert(PyTuple_Check(args) || PyList_Check(args));
189+
if (Py_EnterRecursiveCall(" in __parameter__ calculation")) {
190+
return NULL;
191+
}
192+
189193
const bool is_args_list = PyList_Check(args);
190194
PyObject *tuple_args = NULL;
191195
if (is_args_list) {
@@ -210,9 +214,7 @@ _Py_make_parameters(PyObject *args)
210214
}
211215
int rc = PyObject_HasAttrWithError(t, &_Py_ID(__typing_subst__));
212216
if (rc < 0) {
213-
Py_DECREF(parameters);
214-
Py_XDECREF(tuple_args);
215-
return NULL;
217+
goto error;
216218
}
217219
if (rc) {
218220
iparam += tuple_add(parameters, iparam, t);
@@ -221,18 +223,14 @@ _Py_make_parameters(PyObject *args)
221223
PyObject *subparams;
222224
if (PyObject_GetOptionalAttr(t, &_Py_ID(__parameters__),
223225
&subparams) < 0) {
224-
Py_DECREF(parameters);
225-
Py_XDECREF(tuple_args);
226-
return NULL;
226+
goto error;
227227
}
228228
if (!subparams && (PyTuple_Check(t) || PyList_Check(t))) {
229229
// Recursively call _Py_make_parameters for lists/tuples and
230230
// add the results to the current parameters.
231231
subparams = _Py_make_parameters(t);
232232
if (subparams == NULL) {
233-
Py_DECREF(parameters);
234-
Py_XDECREF(tuple_args);
235-
return NULL;
233+
goto error;
236234
}
237235
}
238236
if (subparams && PyTuple_Check(subparams)) {
@@ -243,7 +241,7 @@ _Py_make_parameters(PyObject *args)
243241
if (_PyTuple_Resize(&parameters, len) < 0) {
244242
Py_DECREF(subparams);
245243
Py_XDECREF(tuple_args);
246-
return NULL;
244+
goto cleanup;
247245
}
248246
}
249247
for (Py_ssize_t j = 0; j < len2; j++) {
@@ -256,13 +254,19 @@ _Py_make_parameters(PyObject *args)
256254
}
257255
if (iparam < len) {
258256
if (_PyTuple_Resize(&parameters, iparam) < 0) {
259-
Py_XDECREF(parameters);
260-
Py_XDECREF(tuple_args);
261-
return NULL;
257+
goto error;
262258
}
263259
}
264260
Py_XDECREF(tuple_args);
261+
Py_LeaveRecursiveCall();
265262
return parameters;
263+
264+
error:
265+
Py_XDECREF(parameters);
266+
Py_XDECREF(tuple_args);
267+
cleanup:
268+
Py_LeaveRecursiveCall();
269+
return NULL;
266270
}
267271

268272
/* If obj is a generic alias, substitute type variables params

0 commit comments

Comments
 (0)