gh-154275: Do not crash on deeply nested `__parameters__` in `GenericAlias` (#154277)

sobolevn <[email protected]>
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/1034e07b7d55642c3a46252e6b0a631c2df588d2
commit: 1034e07b7d55642c3a46252e6b0a631c2df588d2
branch: main
author: sobolevn <[email protected]>
committer: sobolevn <[email protected]>
date: 2026-07-21T01:11:04+03:00
summary:

gh-154275: Do not crash on deeply nested `__parameters__` in `GenericAlias` (#154277)

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 c1f340230159db..106ffdede6fd4e 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,
@@ -5094,6 +5096,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(&parameters, 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(&parameters, 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]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.