[3.15] gh-155752: Do not crash when GenericAlias parameters change during substitution (GH-155761) (#155770)

hugovk <[email protected]>
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/b8a99875499f33194f085f2137dae6e2e8058737
commit: b8a99875499f33194f085f2137dae6e2e8058737
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: hugovk <[email protected]>
date: 2026-08-14T08:55:40Z
summary:

[3.15] gh-155752: Do not crash when GenericAlias parameters change during substitution (GH-155761) (#155770)

gh-155752: Do not crash when GenericAlias parameters change during substitution (GH-155761)

An alias argument can gain __typing_subst__ after __parameters__ has been cached, including during a preparation or substitution callback. Check that the argument is present before indexing the substitution arguments.
(cherry picked from commit c0006faf4f48f01126a8a0752da8f159142e410d)

Co-authored-by: Darius Houle <[email protected]>

files:
A Misc/NEWS.d/next/Core_and_Builtins/2026-08-13-13-50-00.gh-issue-155752.Rp7K2x.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 106ffdede6fd4ef..f99e8f12e941561 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -6053,6 +6053,22 @@ class A:
                     with self.assertRaises(TypeError):
                         a[int]
 
+    def test_parameter_added_after_parameters_cached(self):
+        # gh-155752: GenericAlias parameters are cached before substitution, so
+        # an argument can gain __typing_subst__ after the tuple is calculated.
+        class Parameter:
+            pass
+
+        first = Parameter()
+        first.__typing_subst__ = lambda value: value
+        late = Parameter()
+        alias = types.GenericAlias(dict, (first, late))
+        self.assertEqual(alias.__parameters__, (first,))
+        late.__typing_subst__ = lambda value: value
+
+        with self.assertRaisesRegex(TypeError, "not found in __parameters__"):
+            alias[0]
+
     def test_return_non_tuple_while_unpacking(self):
         # GH-138497: GenericAlias objects didn't ensure that __typing_subst__ actually
         # returned a tuple
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-08-13-13-50-00.gh-issue-155752.Rp7K2x.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-13-13-50-00.gh-issue-155752.Rp7K2x.rst
new file mode 100644
index 000000000000000..300e97ad5d257bc
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-13-13-50-00.gh-issue-155752.Rp7K2x.rst
@@ -0,0 +1,2 @@
+Fix a crash when a :class:`types.GenericAlias` argument gains a
+``__typing_subst__`` hook after the alias parameters have been cached.
diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c
index 71d946a637df1c9..9c3ecd7a453c152 100644
--- a/Objects/genericaliasobject.c
+++ b/Objects/genericaliasobject.c
@@ -524,8 +524,18 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
         }
         if (subst) {
             Py_ssize_t iparam = tuple_index(parameters, nparams, arg);
-            assert(iparam >= 0);
-            arg = PyObject_CallOneArg(subst, argitems[iparam]);
+            if (iparam < 0) {
+                // __parameters__ may be stale if an argument gained
+                // __typing_subst__ after the tuple was computed.
+                PyErr_Format(PyExc_TypeError,
+                             "argument %R with __typing_subst__ was not found "
+                             "in __parameters__",
+                             arg);
+                arg = NULL;
+            }
+            else {
+                arg = PyObject_CallOneArg(subst, argitems[iparam]);
+            }
             Py_DECREF(subst);
         }
         else {

_______________________________________________
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.