https://github.com/python/cpython/commit/d1494f022d2750514c273ab3733f7dd73e7e6fd9 commit: d1494f022d2750514c273ab3733f7dd73e7e6fd9 branch: 3.15 author: Miss Islington (bot) <[email protected]> committer: sobolevn <[email protected]> date: 2026-07-20T22:40:04Z summary:
[3.15] gh-154275: Do not crash on deeply nested `__parameters__` in `GenericAlias` (GH-154277) (#154306) gh-154275: Do not crash on deeply nested `__parameters__` in `GenericAlias` (GH-154277) (cherry picked from commit 1034e07b7d55642c3a46252e6b0a631c2df588d2) Co-authored-by: sobolevn <[email protected]> files: A Misc/NEWS.d/next/Core_and_Builtins/2026-07-20-20-16-08.gh-issue-154275.l961cA.rst M Lib/test/test_typing.py M Objects/genericaliasobject.c diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 986b41b18a2acc..343159bf5dafa3 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -52,6 +52,8 @@ from test.support import ( captured_stderr, cpython_only, requires_docstrings, import_helper, run_code, subTests, EqualToForwardRef, + exceeds_recursion_limit, skip_if_huge_c_stack, skip_wasi_stack_overflow, + skip_emscripten_stack_overflow, ) from test.typinganndata import ( ann_module695, mod_generics_cache, _typed_dict_helper, @@ -5089,6 +5091,17 @@ class MM2(collections.abc.MutableMapping, MutableMapping[str, str]): pass self.assertEqual(MM2.__bases__, (collections.abc.MutableMapping, Generic)) + @cpython_only + @skip_if_huge_c_stack() + @skip_wasi_stack_overflow() + @skip_emscripten_stack_overflow() + def test_parameters_deep_recursion(self): + x = [0] + for _ in range(exceeds_recursion_limit()): + x = [x] + with self.assertRaisesRegex(RecursionError, "in __parameter__ calculation"): + list[x].__parameters__ + def test_orig_bases(self): T = TypeVar('T') class C(typing.Dict[str, T]): ... diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-20-20-16-08.gh-issue-154275.l961cA.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-20-20-16-08.gh-issue-154275.l961cA.rst new file mode 100644 index 00000000000000..998e91c77098e7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-20-20-16-08.gh-issue-154275.l961cA.rst @@ -0,0 +1,2 @@ +Fix a crash when getting deeply nested ``__parameters__`` from a +:class:`types.GenericAlias` objects. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 4e85927def7ea7..5caf5c7086c87a 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -186,6 +186,10 @@ PyObject * _Py_make_parameters(PyObject *args) { assert(PyTuple_Check(args) || PyList_Check(args)); + if (Py_EnterRecursiveCall(" in __parameter__ calculation")) { + return NULL; + } + const bool is_args_list = PyList_Check(args); PyObject *tuple_args = NULL; if (is_args_list) { @@ -210,9 +214,7 @@ _Py_make_parameters(PyObject *args) } int rc = PyObject_HasAttrWithError(t, &_Py_ID(__typing_subst__)); if (rc < 0) { - Py_DECREF(parameters); - Py_XDECREF(tuple_args); - return NULL; + goto error; } if (rc) { iparam += tuple_add(parameters, iparam, t); @@ -221,18 +223,14 @@ _Py_make_parameters(PyObject *args) PyObject *subparams; if (PyObject_GetOptionalAttr(t, &_Py_ID(__parameters__), &subparams) < 0) { - Py_DECREF(parameters); - Py_XDECREF(tuple_args); - return NULL; + goto error; } if (!subparams && (PyTuple_Check(t) || PyList_Check(t))) { // Recursively call _Py_make_parameters for lists/tuples and // add the results to the current parameters. subparams = _Py_make_parameters(t); if (subparams == NULL) { - Py_DECREF(parameters); - Py_XDECREF(tuple_args); - return NULL; + goto error; } } if (subparams && PyTuple_Check(subparams)) { @@ -243,7 +241,7 @@ _Py_make_parameters(PyObject *args) if (_PyTuple_Resize(¶meters, len) < 0) { Py_DECREF(subparams); Py_XDECREF(tuple_args); - return NULL; + goto cleanup; } } for (Py_ssize_t j = 0; j < len2; j++) { @@ -256,13 +254,19 @@ _Py_make_parameters(PyObject *args) } if (iparam < len) { if (_PyTuple_Resize(¶meters, iparam) < 0) { - Py_XDECREF(parameters); - Py_XDECREF(tuple_args); - return NULL; + goto error; } } Py_XDECREF(tuple_args); + Py_LeaveRecursiveCall(); return parameters; + +error: + Py_XDECREF(parameters); + Py_XDECREF(tuple_args); +cleanup: + Py_LeaveRecursiveCall(); + return NULL; } /* If obj is a generic alias, substitute type variables params _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
