https://github.com/python/cpython/commit/40657ad12eb76581b8c25ae5ec389de55fc1ba34
commit: 40657ad12eb76581b8c25ae5ec389de55fc1ba34
branch: 3.14
author: sobolevn <[email protected]>
committer: sobolevn <[email protected]>
date: 2026-07-21T12:18:51+03:00
summary:
[3.14] gh-154275: Do not crash on deeply nested `__parameters__` in
`GenericAlias` (GH-154277) (#154339)
(cherry picked from commit 1034e07b7d55642c3a46252e6b0a631c2df588d2)
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 57cc1db6141e326..c8b11b3cfdc6d89 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, infinite_recursion, requires_docstrings,
import_helper, run_code,
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,
@@ -4926,6 +4928,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 fb96fa9e9f65811..ea3ad683f53ff67 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]