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..ded65e3a371 100644 --- a/src/path.c +++ b/src/path.c @@ -236,7 +236,16 @@ 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) { + if (!PyErr_Occurred()) { + /* PyPy returns NULL without setting an exception */ + PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + } + free(xy); + return -1; + } j = assign_item_to_array(xy, j, op); if (j == -1) { free(xy);