Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Tests/test_image_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import pytest

from PIL import Image

from .helper import assert_image_equal, hopper


Expand Down Expand Up @@ -62,3 +64,21 @@ def test_f_mode() -> None:
im = hopper("F")
with pytest.raises(ValueError):
im.point([])


def test_overstated_length() -> None:
# shouldn't segfault
# see https://github.com/python-pillow/Pillow/issues/9892

class OverstatedLengthSequence:
def __len__(self) -> int:
return 256

def __getitem__(self, index: int) -> float:
if index >= 8:
raise IndexError
return float(index)

im = Image.new("L", (4, 4))
with pytest.raises(ValueError):
im.point(OverstatedLengthSequence(), "F") # type: ignore[arg-type]
18 changes: 18 additions & 0 deletions Tests/test_image_putdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,24 @@ def test_array_F() -> None:
assert len(im.get_flattened_data()) == len(arr)


def test_overstated_length() -> None:
# shouldn't segfault
# see https://github.com/python-pillow/Pillow/issues/9892

class OverstatedLengthSequence:
def __len__(self) -> int:
return 16

def __getitem__(self, index: int) -> float:
if index >= 2:
raise IndexError
return float(index + 1)

im = Image.new("L", (4, 4))
im.putdata(OverstatedLengthSequence()) # type: ignore[arg-type]
assert im.get_flattened_data()[:2] == (1, 2)


def test_not_flattened() -> None:
im = Image.new("L", (1, 1))
with pytest.raises(TypeError):
Expand Down
55 changes: 37 additions & 18 deletions src/_imaging.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,25 +442,36 @@ getlist(PyObject *arg, Py_ssize_t *length, const char *wrong_length, int type) {
return NULL;
}

n = PySequence_Size(arg);
if (length && wrong_length) {
Py_ssize_t reported = PySequence_Size(arg);
if (reported < 0) {
PyErr_Clear();
} else if (reported != *length) {
PyErr_SetString(PyExc_ValueError, wrong_length);
return NULL;
}
}

seq = PySequence_Fast(arg, must_be_sequence);
if (!seq) {
return NULL;
}

n = PySequence_Fast_GET_SIZE(seq);
if (length && wrong_length && n != *length) {
PyErr_SetString(PyExc_ValueError, wrong_length);
Py_DECREF(seq);
return NULL;
}

/* malloc check ok, type & ff is just a sizeof(something)
calloc checks for overflow */
list = calloc(n, type & 0xff);
if (!list) {
Py_DECREF(seq);
return ImagingError_MemoryError();
}

seq = PySequence_Fast(arg, must_be_sequence);
if (!seq) {
free(list);
return NULL;
}

for (i = 0; i < n; i++) {
op = PySequence_Fast_GET_ITEM(seq, i);
// DRY, branch prediction is going to work _really_ well
Expand Down Expand Up @@ -1625,8 +1636,26 @@ _putdata(ImagingObject *self, PyObject *args) {

image = self->image;

n = PyObject_Length(data);
if (image->image8 && PyBytes_Check(data)) {
n = PyBytes_GET_SIZE(data);
} else {
Py_ssize_t reported = PySequence_Size(data);
if (reported < 0) {
PyErr_Clear();
} else if (reported > (Py_ssize_t)image->xsize * (Py_ssize_t)image->ysize) {
PyErr_SetString(PyExc_TypeError, "too many data entries");
return NULL;
}

seq = PySequence_Fast(data, must_be_sequence);
if (!seq) {
PyErr_SetString(PyExc_TypeError, must_be_sequence);
return NULL;
}
n = PySequence_Fast_GET_SIZE(seq);
}
if (n > (Py_ssize_t)image->xsize * (Py_ssize_t)image->ysize) {
Py_XDECREF(seq);
PyErr_SetString(PyExc_TypeError, "too many data entries");
return NULL;
}
Expand Down Expand Up @@ -1667,11 +1696,6 @@ _putdata(ImagingObject *self, PyObject *args) {
}
}
} else {
seq = PySequence_Fast(data, must_be_sequence);
if (!seq) {
PyErr_SetString(PyExc_TypeError, must_be_sequence);
return NULL;
}
double value;
int bigendian = 0;
if (image->type == IMAGING_TYPE_SPECIAL) {
Expand Down Expand Up @@ -1705,11 +1729,6 @@ _putdata(ImagingObject *self, PyObject *args) {
}
} else {
/* 32-bit images */
seq = PySequence_Fast(data, must_be_sequence);
if (!seq) {
PyErr_SetString(PyExc_TypeError, must_be_sequence);
return NULL;
}
switch (image->type) {
case IMAGING_TYPE_INT32:
for (i = x = y = 0; i < n; i++) {
Expand Down
Loading