From 74ab5ac4cda564714545eee52ab789d4bddf1516 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 11 May 2025 23:46:21 +0200 Subject: [PATCH 01/24] Fix memory leak in arrow export using array structure --- src/libImaging/Arrow.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libImaging/Arrow.c b/src/libImaging/Arrow.c index 33ff2ce77..36f4554fc 100644 --- a/src/libImaging/Arrow.c +++ b/src/libImaging/Arrow.c @@ -127,9 +127,7 @@ static void release_const_array(struct ArrowArray *array) { Imaging im = (Imaging)array->private_data; - if (array->n_children == 0) { - ImagingDelete(im); - } + ImagingDelete(im); // Free the buffers and the buffers array if (array->buffers) { From 4984c45da2f6b854cb49dc81fc56372f335d43a0 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Tue, 13 May 2025 10:27:38 +0200 Subject: [PATCH 02/24] valgrind memory leak check --- Makefile | 6 ++++++ Tests/oss-fuzz/python.supp | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Makefile b/Makefile index 53164b08a..fd124d124 100644 --- a/Makefile +++ b/Makefile @@ -99,6 +99,12 @@ valgrind: --log-file=/tmp/valgrind-output \ python3 -m pytest --no-memcheck -vv --valgrind --valgrind-log=/tmp/valgrind-output +.PHONY: valgrind-leak +valgrind-leak: + PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp --leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite \ + --log-file=/tmp/valgrind-output \ + python3 -m pytest -vv --valgrind --valgrind-log=/tmp/valgrind-output Tests/ + .PHONY: readme readme: python3 -c "import markdown2" > /dev/null 2>&1 || python3 -m pip install markdown2 diff --git a/Tests/oss-fuzz/python.supp b/Tests/oss-fuzz/python.supp index 36385d672..1ea2a8eb5 100644 --- a/Tests/oss-fuzz/python.supp +++ b/Tests/oss-fuzz/python.supp @@ -14,3 +14,23 @@ fun:_TIFFReadEncodedTileAndAllocBuffer ... } + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:_PyMem_RawMalloc + fun:PyObject_Malloc + ... +} + +{ + + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + fun:_PyMem_RawRealloc + fun:PyMem_Realloc + ... +} From fdfba982c8d514240435f3ecef540939fb97f120 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Tue, 13 May 2025 10:28:09 +0200 Subject: [PATCH 03/24] fix memory leak in arrow schema --- src/libImaging/Arrow.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libImaging/Arrow.c b/src/libImaging/Arrow.c index 36f4554fc..7d3306123 100644 --- a/src/libImaging/Arrow.c +++ b/src/libImaging/Arrow.c @@ -37,6 +37,10 @@ ReleaseExportedSchema(struct ArrowSchema *array) { child->release = NULL; } // UNDONE -- should I be releasing the children? + free(array->children[i]); + } + if (array->children) { + free(array->children); } // Release dictionary @@ -117,6 +121,7 @@ export_imaging_schema(Imaging im, struct ArrowSchema *schema) { retval = export_named_type(schema->children[0], im->arrow_band_format, "pixel"); if (retval != 0) { free(schema->children[0]); + free(schema->children); schema->release(schema); return retval; } From 84b88a9fbc9c4cfd2bfb7d7a8d18225ee43efedb Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Tue, 13 May 2025 10:58:12 +0200 Subject: [PATCH 04/24] Suppress all python level leaks for now --- Tests/oss-fuzz/python.supp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/oss-fuzz/python.supp b/Tests/oss-fuzz/python.supp index 1ea2a8eb5..4803497ad 100644 --- a/Tests/oss-fuzz/python.supp +++ b/Tests/oss-fuzz/python.supp @@ -18,7 +18,7 @@ { Memcheck:Leak - match-leak-kinds: possible + match-leak-kinds: all fun:malloc fun:_PyMem_RawMalloc fun:PyObject_Malloc @@ -28,7 +28,7 @@ { Memcheck:Leak - match-leak-kinds: possible + match-leak-kinds: all fun:malloc fun:_PyMem_RawRealloc fun:PyMem_Realloc From eaab43540344e26889116262651001f4e42b1630 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Tue, 13 May 2025 10:58:37 +0200 Subject: [PATCH 05/24] Fix leak in webp_encode * Free the output buffer on webp encode error --- src/_webp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/_webp.c b/src/_webp.c index 3aa4c408b..a7809c40e 100644 --- a/src/_webp.c +++ b/src/_webp.c @@ -641,6 +641,10 @@ WebPEncode_wrapper(PyObject *self, PyObject *args) { ImagingSectionLeave(&cookie); WebPPictureFree(&pic); + + output = writer.mem; + ret_size = writer.size; + if (!ok) { int error_code = (&pic)->error_code; char message[50] = ""; @@ -652,10 +656,9 @@ WebPEncode_wrapper(PyObject *self, PyObject *args) { ); } PyErr_Format(PyExc_ValueError, "encoding error %d%s", error_code, message); + free(output); return NULL; } - output = writer.mem; - ret_size = writer.size; { /* I want to truncate the *_size items that get passed into WebP From a9bcd7db884d89bbfe1966c0611f7f3dda1f8f08 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Tue, 13 May 2025 19:50:55 +0200 Subject: [PATCH 06/24] Fix leak of destination image in ImagingUnsharpMask when an error occurs --- src/_imaging.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_imaging.c b/src/_imaging.c index 72f122143..79e0a2b23 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -2226,6 +2226,7 @@ _unsharp_mask(ImagingObject *self, PyObject *args) { } if (!ImagingUnsharpMask(imOut, imIn, radius, percent, threshold)) { + ImagingDelete(imOut); return NULL; } From e2e40c54568236d2504921eb0b335cdab734a7d5 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Tue, 13 May 2025 22:33:27 +0200 Subject: [PATCH 07/24] Fix memory leak in TiffEncode * If setimage errors out, the tiff client state was not freed. --- src/encode.c | 2 ++ src/libImaging/TiffDecode.c | 42 ++++++++++++++++++------------------- src/libImaging/TiffDecode.h | 2 ++ 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/encode.c b/src/encode.c index 7c365a74f..e56494036 100644 --- a/src/encode.c +++ b/src/encode.c @@ -703,6 +703,8 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) { return NULL; } + encoder->cleanup = ImagingLibTiffEncodeCleanup; + num_core_tags = sizeof(core_tags) / sizeof(int); for (pos = 0; pos < tags_size; pos++) { item = PyList_GetItemRef(tags, pos); diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 9a2db95b4..173eca160 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -929,6 +929,27 @@ ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...) { return status; } +int +ImagingLibTiffEncodeCleanup(ImagingCodecState state) { + TIFFSTATE *clientstate = (TIFFSTATE *)state->context; + TIFF *tiff = clientstate->tiff; + + if (!tiff) { + return 0; + } + // TIFFClose in libtiff calls tif_closeproc and TIFFCleanup + if (clientstate->fp) { + // Python will manage the closing of the file rather than libtiff + // So only call TIFFCleanup + TIFFCleanup(tiff); + } else { + // When tif_closeproc refers to our custom _tiffCloseProc though, + // that is fine, as it does not close the file + TIFFClose(tiff); + } + return 0; +} + int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes) { /* One shot encoder. Encode everything to the tiff in the clientstate. @@ -1010,16 +1031,6 @@ ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int byt TRACE(("Encode Error, row %d\n", state->y)); state->errcode = IMAGING_CODEC_BROKEN; - // TIFFClose in libtiff calls tif_closeproc and TIFFCleanup - if (clientstate->fp) { - // Python will manage the closing of the file rather than libtiff - // So only call TIFFCleanup - TIFFCleanup(tiff); - } else { - // When tif_closeproc refers to our custom _tiffCloseProc though, - // that is fine, as it does not close the file - TIFFClose(tiff); - } if (!clientstate->fp) { free(clientstate->data); } @@ -1036,22 +1047,11 @@ ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int byt TRACE(("Error flushing the tiff")); // likely reason is memory. state->errcode = IMAGING_CODEC_MEMORY; - if (clientstate->fp) { - TIFFCleanup(tiff); - } else { - TIFFClose(tiff); - } if (!clientstate->fp) { free(clientstate->data); } return -1; } - TRACE(("Closing \n")); - if (clientstate->fp) { - TIFFCleanup(tiff); - } else { - TIFFClose(tiff); - } // reset the clientstate metadata to use it to read out the buffer. clientstate->loc = 0; clientstate->size = clientstate->eof; // redundant? diff --git a/src/libImaging/TiffDecode.h b/src/libImaging/TiffDecode.h index 22361210d..77808b543 100644 --- a/src/libImaging/TiffDecode.h +++ b/src/libImaging/TiffDecode.h @@ -40,6 +40,8 @@ ImagingLibTiffInit(ImagingCodecState state, int fp, uint32_t offset); extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp); extern int +ImagingLibTiffEncodeCleanup(ImagingCodecState state); +extern int ImagingLibTiffMergeFieldInfo( ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length ); From f792e0b1ef4f25e0df33e8e971056142f9f5248d Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Tue, 13 May 2025 22:48:36 +0200 Subject: [PATCH 08/24] Fix memory leak * Return after setting the error for advanced features without libraqm. Not returning here leads to an alloc that's never freed. --- src/_imagingft.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_imagingft.c b/src/_imagingft.c index 62dab73e5..ca8e556f0 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -425,6 +425,7 @@ text_layout_fallback( "setting text direction, language or font features is not supported " "without libraqm" ); + return 0; } if (PyUnicode_Check(string)) { From 789631c60c3760beeb623cd1728a737502fd9ca3 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Tue, 13 May 2025 23:31:09 +0200 Subject: [PATCH 09/24] Fix memory leak when JpegEncode returns an error. --- src/libImaging/JpegEncode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libImaging/JpegEncode.c b/src/libImaging/JpegEncode.c index 3c11eac22..79a38e12f 100644 --- a/src/libImaging/JpegEncode.c +++ b/src/libImaging/JpegEncode.c @@ -131,6 +131,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { break; default: state->errcode = IMAGING_CODEC_CONFIG; + jpeg_destroy_compress(&context->cinfo); return -1; } @@ -161,6 +162,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { /* Would subsample the green and blue channels, which doesn't make sense */ state->errcode = IMAGING_CODEC_CONFIG; + jpeg_destroy_compress(&context->cinfo); return -1; } jpeg_set_colorspace(&context->cinfo, JCS_RGB); From 7aa6a61d430c585cd10c91c5a73ce13f9f851b9e Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Tue, 13 May 2025 23:50:52 +0200 Subject: [PATCH 10/24] Wrap Makefile --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fd124d124..15f03ba45 100644 --- a/Makefile +++ b/Makefile @@ -101,7 +101,8 @@ valgrind: .PHONY: valgrind-leak valgrind-leak: - PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp --leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite \ + PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp \ + --leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite \ --log-file=/tmp/valgrind-output \ python3 -m pytest -vv --valgrind --valgrind-log=/tmp/valgrind-output Tests/ From fb126af7a6a12e0870e56187257f75f35fe8558b Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 15 May 2025 21:10:48 +0200 Subject: [PATCH 11/24] Adding pytest-valgrind install --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 15f03ba45..bdddecda5 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,7 @@ valgrind: .PHONY: valgrind-leak valgrind-leak: + python3 -c "import pytest_valgrind" > /dev/null 2>&1 || python3 -m pip install pytest-valgrind PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp \ --leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite \ --log-file=/tmp/valgrind-output \ From d5449d576013566100d8a0d41bbc1a756df86da5 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 15 May 2025 21:11:31 +0200 Subject: [PATCH 12/24] Guess so. --- src/libImaging/Arrow.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libImaging/Arrow.c b/src/libImaging/Arrow.c index 7d3306123..0b8c89a07 100644 --- a/src/libImaging/Arrow.c +++ b/src/libImaging/Arrow.c @@ -36,7 +36,6 @@ ReleaseExportedSchema(struct ArrowSchema *array) { child->release(child); child->release = NULL; } - // UNDONE -- should I be releasing the children? free(array->children[i]); } if (array->children) { From 218f055865a4f0abd05ac221c48cf86127907ca9 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 15 May 2025 21:59:02 +0200 Subject: [PATCH 13/24] Add github workflow/test-script --- .github/workflows/test-valgrind-memory.yml | 60 ++++++++++++++++++++++ depends/docker-test-valgrind-memory.sh | 11 ++++ 2 files changed, 71 insertions(+) create mode 100644 .github/workflows/test-valgrind-memory.yml create mode 100644 depends/docker-test-valgrind-memory.sh diff --git a/.github/workflows/test-valgrind-memory.yml b/.github/workflows/test-valgrind-memory.yml new file mode 100644 index 000000000..e6a5f6e77 --- /dev/null +++ b/.github/workflows/test-valgrind-memory.yml @@ -0,0 +1,60 @@ +name: Test Valgrind Memory Leaks + +# like the Docker tests, but running valgrind only on *.c/*.h changes. + +# this is very expensive. Only run on the pull request. +on: + # push: + # branches: + # - "**" + # paths: + # - ".github/workflows/test-valgrind.yml" + # - "**.c" + # - "**.h" + pull_request: + paths: + - ".github/workflows/test-valgrind.yml" + - "**.c" + - "**.h" + - "depends/docker-test-valgrind-memory.sh" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + docker: [ + ubuntu-22.04-jammy-amd64-valgrind, + ] + dockerTag: [main] + + name: ${{ matrix.docker }} + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Build system information + run: python3 .github/workflows/system-info.py + + - name: Docker pull + run: | + docker pull pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} + + - name: Build and Run Valgrind + run: | + # The Pillow user in the docker container is UID 1001 + sudo chown -R 1001 $GITHUB_WORKSPACE + docker run --name pillow_container -e "PILLOW_VALGRIND_TEST=true" -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} /Pillow/depends/docker-test-valgrind-memory.sh + sudo chown -R runner $GITHUB_WORKSPACE diff --git a/depends/docker-test-valgrind-memory.sh b/depends/docker-test-valgrind-memory.sh new file mode 100644 index 000000000..4fd6652d8 --- /dev/null +++ b/depends/docker-test-valgrind-memory.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +## Run this as the test script in the docker valgrind image. +## Note -- can be included directly into the docker image, +## but requires the currnet python.supp. + +source /vpy3/bin/activate +cd /Pillow +make clean +make install +make valgrind-memory From a6b8b3af7709081d8c53818e68b8bc15e9a48f34 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 15 May 2025 22:04:14 +0200 Subject: [PATCH 14/24] executable --- depends/docker-test-valgrind-memory.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 depends/docker-test-valgrind-memory.sh diff --git a/depends/docker-test-valgrind-memory.sh b/depends/docker-test-valgrind-memory.sh old mode 100644 new mode 100755 From 2d506f6f5a478b4a798b3ce71f31b5e5f6f6b60f Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 15 May 2025 22:06:35 +0200 Subject: [PATCH 15/24] correct target --- depends/docker-test-valgrind-memory.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/docker-test-valgrind-memory.sh b/depends/docker-test-valgrind-memory.sh index 4fd6652d8..29fc6f230 100755 --- a/depends/docker-test-valgrind-memory.sh +++ b/depends/docker-test-valgrind-memory.sh @@ -8,4 +8,4 @@ source /vpy3/bin/activate cd /Pillow make clean make install -make valgrind-memory +make valgrind-leak From f1957b49b2d01a9d063aed4000f985b220e30fa0 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Fri, 16 May 2025 12:08:45 +0200 Subject: [PATCH 16/24] Xfail timouts in Valgrind tests * ensure that the env variable is set in the makefile --- Makefile | 4 ++-- Tests/test_file_jpeg.py | 5 +++++ Tests/test_imagefontpil.py | 6 ++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index bdddecda5..82c2c085f 100644 --- a/Makefile +++ b/Makefile @@ -95,14 +95,14 @@ test: .PHONY: valgrind valgrind: python3 -c "import pytest_valgrind" > /dev/null 2>&1 || python3 -m pip install pytest-valgrind - PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp --leak-check=no \ + PILLOW_VALGRIND_TEST=true PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp --leak-check=no \ --log-file=/tmp/valgrind-output \ python3 -m pytest --no-memcheck -vv --valgrind --valgrind-log=/tmp/valgrind-output .PHONY: valgrind-leak valgrind-leak: python3 -c "import pytest_valgrind" > /dev/null 2>&1 || python3 -m pip install pytest-valgrind - PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp \ + PILLOW_VALGRIND_TEST=true PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp \ --leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite \ --log-file=/tmp/valgrind-output \ python3 -m pytest -vv --valgrind --valgrind-log=/tmp/valgrind-output Tests/ diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 79f0ec1a8..fb9f26fc7 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -1034,6 +1034,11 @@ class TestFileJpeg: im.save(f, xmp=b"1" * 65505) @pytest.mark.timeout(timeout=1) + @pytest.mark.xfail( + "PILLOW_VALGRIND_TEST" in os.environ, + reason="Valgrind is slower", + raises=TimeoutError + ) def test_eof(self, monkeypatch: pytest.MonkeyPatch) -> None: # Even though this decoder never says that it is finished # the image should still end when there is no new data diff --git a/Tests/test_imagefontpil.py b/Tests/test_imagefontpil.py index 695aecbde..adce4a75c 100644 --- a/Tests/test_imagefontpil.py +++ b/Tests/test_imagefontpil.py @@ -2,6 +2,7 @@ from __future__ import annotations import struct from io import BytesIO +import os import pytest @@ -73,6 +74,11 @@ def test_decompression_bomb() -> None: @pytest.mark.timeout(4) +@pytest.mark.xfail( + "PILLOW_VALGRIND_TEST" in os.environ, + reason="Valgrind is slower", + raises=TimeoutError +) def test_oom() -> None: glyph = struct.pack( ">hhhhhhhhhh", 1, 0, -32767, -32767, 32767, 32767, -32767, -32767, 32767, 32767 From ff50e30d3e9f1425ca6af95ac044d365c63719d1 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Fri, 16 May 2025 12:47:22 +0200 Subject: [PATCH 17/24] Fix memory leak in text_layout_raqm on 0 length string --- src/_imagingft.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_imagingft.c b/src/_imagingft.c index ca8e556f0..0d70544a5 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -275,6 +275,7 @@ text_layout_raqm( if (!text || !size) { /* return 0 and clean up, no glyphs==no size, and raqm fails with empty strings */ + PyMem_Free(text); goto failed; } set_text = raqm_set_text(rq, text, size); From 20b49a332bd0f0f39660fbb3587cfc4b6d539f0c Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sat, 17 May 2025 10:45:43 +0200 Subject: [PATCH 18/24] Remove timeout as the specific reason, pytest-timeout doesn't raise a timeout error. --- Tests/test_file_jpeg.py | 3 +-- Tests/test_imagefontpil.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index fb9f26fc7..d923020c8 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -1036,8 +1036,7 @@ class TestFileJpeg: @pytest.mark.timeout(timeout=1) @pytest.mark.xfail( "PILLOW_VALGRIND_TEST" in os.environ, - reason="Valgrind is slower", - raises=TimeoutError + reason="Valgrind is slower" ) def test_eof(self, monkeypatch: pytest.MonkeyPatch) -> None: # Even though this decoder never says that it is finished diff --git a/Tests/test_imagefontpil.py b/Tests/test_imagefontpil.py index adce4a75c..bd9bafb55 100644 --- a/Tests/test_imagefontpil.py +++ b/Tests/test_imagefontpil.py @@ -76,8 +76,7 @@ def test_decompression_bomb() -> None: @pytest.mark.timeout(4) @pytest.mark.xfail( "PILLOW_VALGRIND_TEST" in os.environ, - reason="Valgrind is slower", - raises=TimeoutError + reason="Valgrind is slower" ) def test_oom() -> None: glyph = struct.pack( From c35082b619899d5351ba249e8ea23a4412d0c728 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 17 May 2025 08:47:59 +0000 Subject: [PATCH 19/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- Tests/test_file_jpeg.py | 3 +-- Tests/test_imagefontpil.py | 7 ++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index d923020c8..7c33c7517 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -1035,8 +1035,7 @@ class TestFileJpeg: @pytest.mark.timeout(timeout=1) @pytest.mark.xfail( - "PILLOW_VALGRIND_TEST" in os.environ, - reason="Valgrind is slower" + "PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower" ) def test_eof(self, monkeypatch: pytest.MonkeyPatch) -> None: # Even though this decoder never says that it is finished diff --git a/Tests/test_imagefontpil.py b/Tests/test_imagefontpil.py index bd9bafb55..e5b770745 100644 --- a/Tests/test_imagefontpil.py +++ b/Tests/test_imagefontpil.py @@ -1,8 +1,8 @@ from __future__ import annotations +import os import struct from io import BytesIO -import os import pytest @@ -74,10 +74,7 @@ def test_decompression_bomb() -> None: @pytest.mark.timeout(4) -@pytest.mark.xfail( - "PILLOW_VALGRIND_TEST" in os.environ, - reason="Valgrind is slower" -) +@pytest.mark.xfail("PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower") def test_oom() -> None: glyph = struct.pack( ">hhhhhhhhhh", 1, 0, -32767, -32767, 32767, 32767, -32767, -32767, 32767, 32767 From 2603a249df9223133b74c671acfcdc6a51567843 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Fri, 23 May 2025 10:57:03 +0100 Subject: [PATCH 20/24] Update depends/docker-test-valgrind-memory.sh Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- depends/docker-test-valgrind-memory.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/docker-test-valgrind-memory.sh b/depends/docker-test-valgrind-memory.sh index 29fc6f230..5f7805421 100755 --- a/depends/docker-test-valgrind-memory.sh +++ b/depends/docker-test-valgrind-memory.sh @@ -2,7 +2,7 @@ ## Run this as the test script in the docker valgrind image. ## Note -- can be included directly into the docker image, -## but requires the currnet python.supp. +## but requires the current python.supp. source /vpy3/bin/activate cd /Pillow From 60a1a20536fe18cfe936e90140ed56c3eb31bd81 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Fri, 23 May 2025 15:32:46 +0200 Subject: [PATCH 21/24] add timeouts to two more tests --- Tests/test_file_tiff.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 502d9df9a..050bfe578 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -990,6 +990,10 @@ class TestFileTiff: @pytest.mark.timeout(6) @pytest.mark.filterwarnings("ignore:Truncated File Read") + @pytest.mark.xfail( + "PILLOW_VALGRIND_TEST" in os.environ, + reason="Valgrind is slower" + ) def test_timeout(self, monkeypatch: pytest.MonkeyPatch) -> None: with Image.open("Tests/images/timeout-6646305047838720") as im: monkeypatch.setattr(ImageFile, "LOAD_TRUNCATED_IMAGES", True) @@ -1002,6 +1006,10 @@ class TestFileTiff: ], ) @pytest.mark.timeout(2) + @pytest.mark.xfail( + "PILLOW_VALGRIND_TEST" in os.environ, + reason="Valgrind is slower" + ) def test_oom(self, test_file: str) -> None: with pytest.raises(UnidentifiedImageError): with pytest.warns(UserWarning): From c63db77db3850c51df38af8f4a96f5c13f286b42 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 13:37:02 +0000 Subject: [PATCH 22/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- Tests/test_file_tiff.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 050bfe578..b6985b83b 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -991,8 +991,7 @@ class TestFileTiff: @pytest.mark.timeout(6) @pytest.mark.filterwarnings("ignore:Truncated File Read") @pytest.mark.xfail( - "PILLOW_VALGRIND_TEST" in os.environ, - reason="Valgrind is slower" + "PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower" ) def test_timeout(self, monkeypatch: pytest.MonkeyPatch) -> None: with Image.open("Tests/images/timeout-6646305047838720") as im: @@ -1007,8 +1006,7 @@ class TestFileTiff: ) @pytest.mark.timeout(2) @pytest.mark.xfail( - "PILLOW_VALGRIND_TEST" in os.environ, - reason="Valgrind is slower" + "PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower" ) def test_oom(self, test_file: str) -> None: with pytest.raises(UnidentifiedImageError): From 98cf15e9e487cbc53b101498d43cc0cc141ee7e7 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Fri, 30 May 2025 10:35:13 +0100 Subject: [PATCH 23/24] Update depends/docker-test-valgrind-memory.sh Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- depends/docker-test-valgrind-memory.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/docker-test-valgrind-memory.sh b/depends/docker-test-valgrind-memory.sh index 5f7805421..f0d1d851d 100755 --- a/depends/docker-test-valgrind-memory.sh +++ b/depends/docker-test-valgrind-memory.sh @@ -1,7 +1,7 @@ #!/bin/bash -## Run this as the test script in the docker valgrind image. -## Note -- can be included directly into the docker image, +## Run this as the test script in the Docker valgrind image. +## Note -- can be included directly into the Docker image, ## but requires the current python.supp. source /vpy3/bin/activate From 399b6c1045ff2387e7db8206e72baec33f996030 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Fri, 30 May 2025 10:40:07 +0100 Subject: [PATCH 24/24] Update Makefile Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4f63cfe02..27d70dcb7 100644 --- a/Makefile +++ b/Makefile @@ -110,7 +110,7 @@ valgrind-leak: PILLOW_VALGRIND_TEST=true PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp \ --leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite \ --log-file=/tmp/valgrind-output \ - python3 -m pytest -vv --valgrind --valgrind-log=/tmp/valgrind-output Tests/ + python3 -m pytest -vv --valgrind --valgrind-log=/tmp/valgrind-output .PHONY: readme readme: