From 674152671ad55b8608acdd011e46d9ff9b508f3a Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 21 Jul 2026 01:11:04 +0300 Subject: [PATCH 1/3] [3.13] gh-154275: Do not crash on deeply nested `__parameters__` in `GenericAlias` (GH-154277) (cherry picked from commit 1034e07b7d55642c3a46252e6b0a631c2df588d2) Co-authored-by: sobolevn --- Lib/test/test_typing.py | 17 +++++++++++- ...-07-20-20-16-08.gh-issue-154275.l961cA.rst | 2 ++ Objects/genericaliasobject.c | 26 ++++++++++++------- 3 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-20-20-16-08.gh-issue-154275.l961cA.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 92b90fac3575df6..13da9c94e52f7f5 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -45,7 +45,11 @@ import weakref import types -from test.support import captured_stderr, cpython_only, infinite_recursion, requires_docstrings, import_helper +from test.support import ( + captured_stderr, cpython_only, infinite_recursion, requires_docstrings, import_helper, + exceeds_recursion_limit, skip_if_huge_c_stack, skip_wasi_stack_overflow, + skip_emscripten_stack_overflow, +) from test.support.testcase import ExtraAssertions from test.typinganndata import ann_module695, mod_generics_cache, _typed_dict_helper @@ -4826,6 +4830,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 000000000000000..998e91c77098e75 --- /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 157facd16a7e64f..eb4c5ef8d36b7d2 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -244,11 +244,16 @@ tuple_extend(PyObject **dst, Py_ssize_t dstindex, PyObject * _Py_make_parameters(PyObject *args) { + if (Py_EnterRecursiveCall(" in __parameter__ calculation")) { + return NULL; + } + Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t len = nargs; PyObject *parameters = PyTuple_New(len); - if (parameters == NULL) - return NULL; + if (parameters == NULL) { + goto cleanup; + } Py_ssize_t iparam = 0; for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { PyObject *t = PyTuple_GET_ITEM(args, iarg); @@ -258,8 +263,7 @@ _Py_make_parameters(PyObject *args) } int rc = PyObject_HasAttrWithError(t, &_Py_ID(__typing_subst__)); if (rc < 0) { - Py_DECREF(parameters); - return NULL; + goto error; } if (rc) { iparam += tuple_add(parameters, iparam, t); @@ -268,8 +272,7 @@ _Py_make_parameters(PyObject *args) PyObject *subparams; if (PyObject_GetOptionalAttr(t, &_Py_ID(__parameters__), &subparams) < 0) { - Py_DECREF(parameters); - return NULL; + goto error; } if (subparams && PyTuple_Check(subparams)) { Py_ssize_t len2 = PyTuple_GET_SIZE(subparams); @@ -278,7 +281,7 @@ _Py_make_parameters(PyObject *args) len += needed; if (_PyTuple_Resize(¶meters, len) < 0) { Py_DECREF(subparams); - return NULL; + goto cleanup; } } for (Py_ssize_t j = 0; j < len2; j++) { @@ -291,11 +294,16 @@ _Py_make_parameters(PyObject *args) } if (iparam < len) { if (_PyTuple_Resize(¶meters, iparam) < 0) { - Py_XDECREF(parameters); - return NULL; + goto error; } } return parameters; + +error: + Py_XDECREF(parameters); +cleanup: + Py_LeaveRecursiveCall(); + return NULL; } /* If obj is a generic alias, substitute type variables params From 3dcd969d26180bdb09a485fa1394f3d1775deda6 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 21 Jul 2026 12:58:46 +0300 Subject: [PATCH 2/3] Remove the test for 3.13 --- Lib/test/test_typing.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 13da9c94e52f7f5..92b90fac3575df6 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -45,11 +45,7 @@ import weakref import types -from test.support import ( - captured_stderr, cpython_only, infinite_recursion, requires_docstrings, import_helper, - exceeds_recursion_limit, skip_if_huge_c_stack, skip_wasi_stack_overflow, - skip_emscripten_stack_overflow, -) +from test.support import captured_stderr, cpython_only, infinite_recursion, requires_docstrings, import_helper from test.support.testcase import ExtraAssertions from test.typinganndata import ann_module695, mod_generics_cache, _typed_dict_helper @@ -4830,17 +4826,6 @@ 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]): ... From 4266cd4da71bec5c7fdb8a6d759cafbbabb8d3f3 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 21 Jul 2026 13:05:04 +0300 Subject: [PATCH 3/3] gh-154275: Fix cleanup code in `_Py_make_parameters` --- Objects/genericaliasobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index eb4c5ef8d36b7d2..fb959dcefd8ad09 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -297,6 +297,7 @@ _Py_make_parameters(PyObject *args) goto error; } } + Py_LeaveRecursiveCall(); return parameters; error: