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 <storchaka@gmail.com>
This commit is contained in:
Peter Bierma
2025-09-11 06:39:09 -04:00
committed by GitHub
parent 011179a79a
commit 1da989be74
3 changed files with 31 additions and 0 deletions

View File

@@ -5844,6 +5844,23 @@ class GenericTests(BaseTestCase):
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):

View File

@@ -0,0 +1,2 @@
Fix a crash when a generic object's ``__typing_subst__`` returns an object
that isn't a :class:`tuple`.

View File

@@ -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;
}
}