From 7fac3d710909a6b39a77ed330ae4dd0051a5347e Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Thu, 11 Sep 2025 06:39:09 -0400 Subject: [PATCH] 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 --- Lib/test/test_typing.py | 17 +++++++++++++++++ ...25-09-03-17-00-30.gh-issue-138479.qUxgWs.rst | 2 ++ Objects/genericaliasobject.c | 12 ++++++++++++ 3 files changed, 31 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 cd552f9887d8a0..2aae92c5ea1021 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -5797,6 +5797,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 3bb961aa2b619d..2ef2ec1c54a234 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -525,12 +525,24 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje return NULL; } if (unpack) { + if (!PyTuple_Check(arg)) { + Py_DECREF(newargs); + Py_DECREF(item); + Py_XDECREF(tuple_args); + 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); Py_XDECREF(tuple_args); + assert(newargs == NULL); return NULL; } }