From 2ac5f2a8df9881b1ea3212580997f4bf7857d90c Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Thu, 11 Sep 2025 06:39:09 -0400 Subject: [PATCH 1/2] gh-138479: Ensure that `__typing_subst__` returns a tuple (GH-138482) Raise an exception if __typing_subst__ returns a non-tuple object. --------- Co-authored-by: Serhiy Storchaka (cherry picked from commit 1da989be74eaa94590ec28e750e5352de1ead227) --- Lib/test/test_typing.py | 17 +++++++++++++++++ ...25-09-03-17-00-30.gh-issue-138479.qUxgWs.rst | 2 ++ Objects/genericaliasobject.c | 11 +++++++++++ 3 files changed, 30 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-09-03-17-00-30.gh-issue-138479.qUxgWs.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index e1115809d4f390..5f49bf757096f0 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -5706,6 +5706,23 @@ class A: with self.assertRaises(TypeError): a[int] + def test_return_non_tuple_while_unpacking(self): + # GH-138497: GenericAlias objects didn't ensure that __typing_subst__ actually + # returned a tuple + class EvilTypeVar: + __typing_is_unpacked_typevartuple__ = True + def __typing_prepare_subst__(*_): + return None # any value + def __typing_subst__(*_): + return 42 # not tuple + + evil = EvilTypeVar() + # Create a dummy TypeAlias that will be given the evil generic from + # above. + type type_alias[*_] = 0 + with self.assertRaisesRegex(TypeError, ".+__typing_subst__.+tuple.+int.*"): + type_alias[evil][0] + class ClassVarTests(BaseTestCase): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-03-17-00-30.gh-issue-138479.qUxgWs.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-03-17-00-30.gh-issue-138479.qUxgWs.rst new file mode 100644 index 00000000000000..c94640af3b053c --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-03-17-00-30.gh-issue-138479.qUxgWs.rst @@ -0,0 +1,2 @@ +Fix a crash when a generic object's ``__typing_subst__`` returns an object +that isn't a :class:`tuple`. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index bf1838061e9eb1..4bb84f054dd3dd 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -517,11 +517,22 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje return NULL; } if (unpack) { + if (!PyTuple_Check(arg)) { + Py_DECREF(newargs); + Py_DECREF(item); + PyObject *original = PyTuple_GET_ITEM(args, iarg); + PyErr_Format(PyExc_TypeError, + "expected __typing_subst__ of %T objects to return a tuple, not %T", + original, arg); + Py_DECREF(arg); + return NULL; + } jarg = tuple_extend(&newargs, jarg, &PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg)); Py_DECREF(arg); if (jarg < 0) { Py_DECREF(item); + assert(newargs == NULL); return NULL; } } From 6135142687e755466d7a389fe3d4b0b79b748d60 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Thu, 11 Sep 2025 06:45:45 -0400 Subject: [PATCH 2/2] [3.13] gh-138479: Ensure that `__typing_subst__` returns a tuple (GH-138482) Raise an exception if __typing_subst__ returns a non-tuple object. --------- (cherry picked from commit 1da989be74eaa94590ec28e750e5352de1ead227) Co-authored-by: Peter Bierma Co-authored-by: Serhiy Storchaka