From 5281dc170ca6233e8ea0fb76e90479d940297d03 Mon Sep 17 00:00:00 2001 From: Serotav Date: Thu, 4 Jun 2026 13:36:13 +0200 Subject: [PATCH 1/2] Prevent reusing ImagingDecoder.setimage --- Tests/test_imagefile.py | 8 ++++++++ src/decode.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index 5177059055a..3cca0681866 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -301,6 +301,14 @@ def setup_class(cls) -> None: class TestPyDecoder(CodecsTest): + def test_c_decoder_setimage_once(self) -> None: + im = Image.new("L", (1, 1)) + decoder = Image._getdecoder("L", "raw", "L") + + decoder.setimage(im.im, (0, 0, 1, 1)) + with pytest.raises(ValueError, match="decoder already has an image"): + decoder.setimage(im.im, (0, 0, 1, 1)) + def test_setimage(self) -> None: buf = BytesIO(b"\x00" * 255) diff --git a/src/decode.c b/src/decode.c index 5c6c250987d..fc46d9d3bee 100644 --- a/src/decode.c +++ b/src/decode.c @@ -53,6 +53,7 @@ typedef struct { Imaging im; PyObject *lock; int pulls_fd; + int has_image; } ImagingDecoderObject; static PyTypeObject ImagingDecoderType; @@ -92,6 +93,7 @@ PyImaging_DecoderNew(int contextsize) { /* Target image */ decoder->lock = NULL; decoder->im = NULL; + decoder->has_image = 0; /* Initialize the cleanup function pointer */ decoder->cleanup = NULL; @@ -168,6 +170,10 @@ _setimage(ImagingDecoderObject *decoder, PyObject *args) { if (!im) { return NULL; } + if (decoder->has_image) { + PyErr_SetString(PyExc_ValueError, "decoder already has an image"); + return NULL; + } if (extents == Py_None) { x0 = 0; y0 = 0; @@ -234,6 +240,7 @@ _setimage(ImagingDecoderObject *decoder, PyObject *args) { Py_INCREF(op); Py_XDECREF(decoder->lock); decoder->lock = op; + decoder->has_image = 1; Py_RETURN_NONE; } From 6abe5dec2d1c635d1dd19ee3d7253a50f352aa84 Mon Sep 17 00:00:00 2001 From: Andrew Murray <3112309+radarhere@users.noreply.github.com> Date: Fri, 5 Jun 2026 05:08:05 +1000 Subject: [PATCH 2/2] Simplify code (#1) * Move test * Simplify code --------- Co-authored-by: Andrew Murray --- Tests/test_image.py | 8 ++++++++ Tests/test_imagefile.py | 8 -------- src/decode.c | 11 ++++------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index 81bd4729926..141dd960f15 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -1122,6 +1122,14 @@ def test_constants(self) -> None: for name in enum.__members__: assert getattr(Image, name) == enum[name] + def test_decoder_setimage_once(self) -> None: + im = Image.new("L", (1, 1)) + decoder = Image._getdecoder("L", "raw", "L") + + decoder.setimage(im.im, None) + with pytest.raises(ValueError, match="decoder already has an image"): + decoder.setimage(im.im, None) + @pytest.mark.parametrize( "path", [ diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index 3cca0681866..5177059055a 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -301,14 +301,6 @@ def setup_class(cls) -> None: class TestPyDecoder(CodecsTest): - def test_c_decoder_setimage_once(self) -> None: - im = Image.new("L", (1, 1)) - decoder = Image._getdecoder("L", "raw", "L") - - decoder.setimage(im.im, (0, 0, 1, 1)) - with pytest.raises(ValueError, match="decoder already has an image"): - decoder.setimage(im.im, (0, 0, 1, 1)) - def test_setimage(self) -> None: buf = BytesIO(b"\x00" * 255) diff --git a/src/decode.c b/src/decode.c index fc46d9d3bee..5055ebb03fc 100644 --- a/src/decode.c +++ b/src/decode.c @@ -53,7 +53,6 @@ typedef struct { Imaging im; PyObject *lock; int pulls_fd; - int has_image; } ImagingDecoderObject; static PyTypeObject ImagingDecoderType; @@ -93,7 +92,6 @@ PyImaging_DecoderNew(int contextsize) { /* Target image */ decoder->lock = NULL; decoder->im = NULL; - decoder->has_image = 0; /* Initialize the cleanup function pointer */ decoder->cleanup = NULL; @@ -170,10 +168,6 @@ _setimage(ImagingDecoderObject *decoder, PyObject *args) { if (!im) { return NULL; } - if (decoder->has_image) { - PyErr_SetString(PyExc_ValueError, "decoder already has an image"); - return NULL; - } if (extents == Py_None) { x0 = 0; y0 = 0; @@ -210,6 +204,10 @@ _setimage(ImagingDecoderObject *decoder, PyObject *args) { return NULL; } + if (decoder->im != NULL) { + PyErr_SetString(PyExc_ValueError, "decoder already has an image"); + return NULL; + } decoder->im = im; state = &decoder->state; @@ -240,7 +238,6 @@ _setimage(ImagingDecoderObject *decoder, PyObject *args) { Py_INCREF(op); Py_XDECREF(decoder->lock); decoder->lock = op; - decoder->has_image = 1; Py_RETURN_NONE; }