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]

Reply via email to