From dac3517c86a9aa6fac978eb0b3acc0b303a9b5cd Mon Sep 17 00:00:00 2001 From: Quinn Xu Date: Thu, 29 Oct 2026 10:18:22 -0700 Subject: [PATCH 1/2] Do not read past the end of a tuple subclass with a larger __len__ --- Tests/test_imagepath.py | 9 +++++++++ src/path.c | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py index 1e291ba7c46..9f9bff85a6b 100644 --- a/Tests/test_imagepath.py +++ b/Tests/test_imagepath.py @@ -216,6 +216,15 @@ def test_overflow_segfault() -> None: x[i] = b"0" * 16 +def test_tuple_subclass_with_larger_len() -> None: + class LargerLen(tuple[float, ...]): + def __len__(self) -> int: + return 10 + + with pytest.raises(IndexError): + ImagePath.Path(LargerLen((0.0,))) + + def test_compact_empty_path() -> None: p = ImagePath.Path(0) assert p.compact() == 0 diff --git a/src/path.c b/src/path.c index 16f58cf70e4..fa48c2e4323 100644 --- a/src/path.c +++ b/src/path.c @@ -236,7 +236,12 @@ PyPath_Flatten(PyObject *data, double **pxy) { } } else if (PyTuple_Check(data)) { for (i = 0; i < n; i++) { - PyObject *op = PyTuple_GET_ITEM(data, i); + /* Checked access, as a subclass may report a larger __len__ */ + PyObject *op = PyTuple_GetItem(data, i); + if (op == NULL) { + free(xy); + return -1; + } j = assign_item_to_array(xy, j, op); if (j == -1) { free(xy); From b218ce7dc794500c75c4f9e87a88c812c5404d6b Mon Sep 17 00:00:00 2001 From: Quinn Xu Date: Tue, 3 Nov 2026 10:06:11 -0800 Subject: [PATCH 2/2] Set IndexError when PyPy returns NULL without an exception --- src/path.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/path.c b/src/path.c index fa48c2e4323..ded65e3a371 100644 --- a/src/path.c +++ b/src/path.c @@ -239,6 +239,10 @@ PyPath_Flatten(PyObject *data, double **pxy) { /* Checked access, as a subclass may report a larger __len__ */ PyObject *op = PyTuple_GetItem(data, i); if (op == NULL) { + if (!PyErr_Occurred()) { + /* PyPy returns NULL without setting an exception */ + PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + } free(xy); return -1; }