diff --git a/.appveyor.yml b/.appveyor.yml index a77033ec1..4e2ca1071 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -32,7 +32,7 @@ install: c:\pillow\winbuild\build\build_dep_all.cmd $host.SetShouldExit(0) - path C:\pillow\winbuild\build\bin;%PATH% -- '%PYTHON%\%EXECUTABLE% -m pip install -U "setuptools>=49.3.2"' +- '%PYTHON%\%EXECUTABLE% -m pip install -U setuptools' build_script: - ps: | @@ -45,6 +45,7 @@ test_script: - cd c:\pillow - '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov' - c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE% +- '%PYTHON%\%EXECUTABLE% -c "from PIL import Image"' - '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests' #- '%PYTHON%\%EXECUTABLE% test-installed.py -v -s %TEST_OPTIONS%' TODO TEST_OPTIONS with pytest? diff --git a/.ci/test.sh b/.ci/test.sh index 5a19ec9b4..9d2c123da 100755 --- a/.ci/test.sh +++ b/.ci/test.sh @@ -2,4 +2,6 @@ set -e -python -bb -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term Tests +python3 -c "from PIL import Image" + +python3 -bb -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term Tests diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 3c658293e..bddeb6150 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,12 +34,12 @@ jobs: python-version: 3.8 - name: Build system information - run: python .github/workflows/system-info.py + run: python3 .github/workflows/system-info.py - name: Install dependencies run: | - python -m pip install -U pip - python -m pip install -U tox + python3 -m pip install -U pip + python3 -m pip install -U tox - name: Lint run: tox -e lint diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index eb173c359..2ecc27460 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -41,7 +41,7 @@ jobs: - uses: actions/checkout@v2 - name: Build system information - run: python .github/workflows/system-info.py + run: python3 .github/workflows/system-info.py - name: Set up QEMU if: "matrix.qemu-arch" diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index c5aa133cb..c82e0b98b 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -246,8 +246,6 @@ jobs: ${{ matrix.package }}-python3-olefile \ ${{ matrix.package }}-python3-pip \ ${{ matrix.package }}-python3-pyqt5 \ - ${{ matrix.package }}-python3-pytest \ - ${{ matrix.package }}-python3-pytest-cov \ ${{ matrix.package }}-python3-setuptools \ ${{ matrix.package }}-freetype \ ${{ matrix.package }}-ghostscript \ @@ -260,7 +258,7 @@ jobs: ${{ matrix.package }}-openjpeg2 \ subversion - python3 -m pip install pyroma + python3 -m pip install pyroma pytest pytest-cov pushd depends && ./install_extra_test_images.sh && popd @@ -270,6 +268,7 @@ jobs: - name: Test Pillow run: | python3 selftest.py --installed + python3 -c "from PIL import Image" python3 -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests - name: Upload coverage diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d127916ea..4064a0589 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,7 +58,7 @@ jobs: ${{ matrix.os }}-${{ matrix.python-version }}- - name: Build system information - run: python .github/workflows/system-info.py + run: python3 .github/workflows/system-info.py - name: Install Linux dependencies if: startsWith(matrix.os, 'ubuntu') diff --git a/CHANGES.rst b/CHANGES.rst index 6296c09c7..4ad7bb8d3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,24 @@ Changelog (Pillow) ================== +8.2.0 (unreleased) +------------------ + +- Deprecate Tk/Tcl 8.4, to be removed in Pillow 10 (2023-01-02) #5216 + [radarhere] + +- Added tk version to pilinfo #5226 + [radarhere, nulano] + +- Support for ignoring tests when running valgrind #5150 + [wiredfool, radarhere, hugovk] + +- PyModule_AddObject fix for Python 3.10 #5194 + [radarhere] + +- OSS-Fuzz support #5189 + [wiredfool, radarhere] + 8.1.0 (2020-01-02) ------------------ diff --git a/Tests/conftest.py b/Tests/conftest.py index 082f2f7c3..6f9945204 100644 --- a/Tests/conftest.py +++ b/Tests/conftest.py @@ -1,4 +1,7 @@ import io +import warnings + +import pytest def pytest_report_header(config): @@ -10,3 +13,19 @@ def pytest_report_header(config): return out.getvalue() except Exception as e: return f"pytest_report_header failed: {e}" + + +def pytest_configure(config): + # We're marking some tests to ignore valgrind errors and XFAIL them. + # Ensure that the mark is defined + # even in cases where pytest-valgrind isn't installed + + with warnings.catch_warnings(): + warnings.simplefilter("error") + try: + getattr(pytest.mark, "valgrind_known_error") + except Exception: + config.addinivalue_line( + "markers", + "valgrind_known_error: Tests that have known issues with valgrind", + ) diff --git a/Tests/oss-fuzz/fuzz_pillow.py b/Tests/oss-fuzz/fuzz_pillow.py new file mode 100644 index 000000000..894068f63 --- /dev/null +++ b/Tests/oss-fuzz/fuzz_pillow.py @@ -0,0 +1,48 @@ +#!/usr/bin/python3 + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import io +import sys +import warnings + +import atheris_no_libfuzzer as atheris + +from PIL import Image, ImageFile, ImageFilter + + +def TestOneInput(data): + try: + with Image.open(io.BytesIO(data)) as im: + im.rotate(45) + im.filter(ImageFilter.DETAIL) + im.save(io.BytesIO(), "BMP") + except Exception: + # We're catching all exceptions because Pillow's exceptions are + # directly inheriting from Exception. + return + return + + +def main(): + ImageFile.LOAD_TRUNCATED_IMAGES = True + warnings.filterwarnings("ignore") + warnings.simplefilter("error", Image.DecompressionBombWarning) + atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True) + atheris.Fuzz() + + +if __name__ == "__main__": + main() diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index f585a0669..1e56498ba 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -59,6 +59,7 @@ def test_invalid_file(): EpsImagePlugin.EpsImageFile(invalid_file) +@pytest.mark.valgrind_known_error(reason="Known Failing") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") def test_cmyk(): with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image: diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index ff469d15c..435ecbaa7 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -114,6 +114,7 @@ class TestFileJpeg: assert test(100, 200) == (100, 200) assert test(0) is None # square pixels + @pytest.mark.valgrind_known_error(reason="Known Failing") def test_icc(self, tmp_path): # Test ICC support with Image.open("Tests/images/rgb.jpg") as im1: @@ -153,6 +154,7 @@ class TestFileJpeg: test(ImageFile.MAXBLOCK + 1) # full buffer block plus one byte test(ImageFile.MAXBLOCK * 4 + 3) # large block + @pytest.mark.valgrind_known_error(reason="Known Failing") def test_large_icc_meta(self, tmp_path): # https://github.com/python-pillow/Pillow/issues/148 # Sometimes the meta data on the icc_profile block is bigger than @@ -419,6 +421,7 @@ class TestFileJpeg: with Image.open(filename): pass + @pytest.mark.valgrind_known_error(reason="Known Failing") def test_truncated_jpeg_should_read_all_the_data(self): filename = "Tests/images/truncated_jpeg.jpg" ImageFile.LOAD_TRUNCATED_IMAGES = True @@ -437,6 +440,7 @@ class TestFileJpeg: with pytest.raises(OSError): im.load() + @pytest.mark.valgrind_known_error(reason="Known Failing") def test_qtables(self, tmp_path): def _n_qtables_helper(n, test_file): with Image.open(test_file) as im: @@ -720,6 +724,7 @@ class TestFileJpeg: # OSError for unidentified image. assert im.info.get("dpi") == (72, 72) + @pytest.mark.valgrind_known_error(reason="Known Failing") def test_exif_x_resolution(self, tmp_path): with Image.open("Tests/images/flower.jpg") as im: exif = im.getexif() @@ -750,6 +755,7 @@ class TestFileJpeg: # Act / Assert assert im._getexif()[306] == "2017:03:13 23:03:09" + @pytest.mark.valgrind_known_error(reason="Backtrace in Python Core") def test_photoshop(self): with Image.open("Tests/images/photoshop-200dpi.jpg") as im: assert im.info["photoshop"][0x03ED] == { diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 7d3e10c24..5fe10bea9 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -9,6 +9,7 @@ from ctypes import c_float import pytest from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features +from PIL.TiffImagePlugin import SUBIFD from .helper import ( assert_image_equal, @@ -185,6 +186,7 @@ class TestFileLibTiff(LibTiffTestCase): for field in requested_fields: assert field in reloaded, f"{field} not in metadata" + @pytest.mark.valgrind_known_error(reason="Known invalid metadata") def test_additional_metadata(self, tmp_path): # these should not crash. Seriously dummy data, most of it doesn't make # any sense, so we're running up against limits where we're asking @@ -323,6 +325,14 @@ class TestFileLibTiff(LibTiffTestCase): ) TiffImagePlugin.WRITE_LIBTIFF = False + def test_subifd(self, tmp_path): + outfile = str(tmp_path / "temp.tif") + with Image.open("Tests/images/g4_orientation_6.tif") as im: + im.tag_v2[SUBIFD] = 10000 + + # Should not segfault + im.save(outfile) + def test_xmlpacket_tag(self, tmp_path): TiffImagePlugin.WRITE_LIBTIFF = True @@ -814,12 +824,14 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) + @pytest.mark.valgrind_known_error(reason="Known Failing") @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_strip_ycbcr_jpeg_2x2_sampling(self): infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif" with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5) + @pytest.mark.valgrind_known_error(reason="Known Failing") @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_strip_ycbcr_jpeg_1x1_sampling(self): infile = "Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif" @@ -831,12 +843,14 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) + @pytest.mark.valgrind_known_error(reason="Known Failing") @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_tiled_ycbcr_jpeg_1x1_sampling(self): infile = "Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif" with Image.open(infile) as im: assert_image_equal_tofile(im, "Tests/images/flower2.jpg") + @pytest.mark.valgrind_known_error(reason="Known Failing") @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_tiled_ycbcr_jpeg_2x2_sampling(self): infile = "Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif" @@ -864,6 +878,7 @@ class TestFileLibTiff(LibTiffTestCase): assert_image_similar(base_im, im, 0.7) + @pytest.mark.valgrind_known_error(reason="Backtrace in Python Core") def test_sampleformat_not_corrupted(self): # Assert that a TIFF image with SampleFormat=UINT tag is not corrupted # when saving to a new file. diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py index 3e23beae7..e5bba483a 100644 --- a/Tests/test_file_pdf.py +++ b/Tests/test_file_pdf.py @@ -85,6 +85,7 @@ def test_unsupported_mode(tmp_path): im.save(outfile) +@pytest.mark.valgrind_known_error(reason="Known Failing") def test_save_all(tmp_path): # Single frame image helper_save_as_pdf(tmp_path, "RGB", save_all=True) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index 9028aaf23..289c09767 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -571,8 +571,8 @@ class TestFilePng: assert len(chunks) == 3 def test_read_private_chunks(self): - im = Image.open("Tests/images/exif.png") - assert im.private_chunks == [(b"orNT", b"\x01")] + with Image.open("Tests/images/exif.png") as im: + assert im.private_chunks == [(b"orNT", b"\x01")] def test_roundtrip_private_chunk(self): # Check private chunk roundtripping @@ -654,6 +654,7 @@ class TestFilePng: exif = reloaded._getexif() assert exif[274] == 1 + @pytest.mark.valgrind_known_error(reason="Known Failing") def test_exif_from_jpg(self, tmp_path): with Image.open("Tests/images/pil_sample_rgb.jpg") as im: test_file = str(tmp_path / "temp.png") diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index bb1bbda3e..f644ef887 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -4,7 +4,7 @@ from io import BytesIO import pytest from PIL import Image, TiffImagePlugin -from PIL.TiffImagePlugin import RESOLUTION_UNIT, SUBIFD, X_RESOLUTION, Y_RESOLUTION +from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION from .helper import ( assert_image_equal, @@ -161,14 +161,6 @@ class TestFileTiff: reloaded.load() assert (round(dpi), round(dpi)) == reloaded.info["dpi"] - def test_subifd(self, tmp_path): - outfile = str(tmp_path / "temp.tif") - with Image.open("Tests/images/g4_orientation_6.tif") as im: - im.tag_v2[SUBIFD] = 10000 - - # Should not segfault - im.save(outfile) - def test_save_setting_missing_resolution(self): b = BytesIO() Image.open("Tests/images/10ct_32bit_128.tiff").save( diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index a2a05f96b..cb133e2c5 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -1,5 +1,7 @@ from io import BytesIO +import pytest + from PIL import Image from .helper import skip_unless_feature @@ -39,6 +41,7 @@ def test_read_exif_metadata_without_prefix(): assert exif[305] == "Adobe Photoshop CS6 (Macintosh)" +@pytest.mark.valgrind_known_error(reason="Known Failing") def test_write_exif_metadata(): file_path = "Tests/images/flower.jpg" test_buffer = BytesIO() @@ -71,6 +74,7 @@ def test_read_icc_profile(): assert icc == expected_icc +@pytest.mark.valgrind_known_error(reason="Known Failing") def test_write_icc_metadata(): file_path = "Tests/images/flower2.jpg" test_buffer = BytesIO() @@ -88,6 +92,7 @@ def test_write_icc_metadata(): assert webp_icc_profile == expected_icc_profile, "Webp ICC didn't match" +@pytest.mark.valgrind_known_error(reason="Known Failing") def test_read_no_exif(): file_path = "Tests/images/flower.jpg" test_buffer = BytesIO() diff --git a/Tests/test_image.py b/Tests/test_image.py index f2a1917e8..ade9d03c9 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -652,6 +652,7 @@ class TestImage: assert not fp.closed + @pytest.mark.valgrind_known_error(reason="Known Failing") def test_exif_jpeg(self, tmp_path): with Image.open("Tests/images/exif-72dpi-int.jpg") as im: # Little endian exif = im.getexif() diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index ef4ca4101..69449198e 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -455,6 +455,7 @@ class TestCoreResampleBox: tiled.paste(tile, (x0, y0)) return tiled + @pytest.mark.valgrind_known_error(reason="Known Failing") def test_tiles(self): with Image.open("Tests/images/flower.jpg") as im: assert im.size == (480, 360) @@ -465,6 +466,7 @@ class TestCoreResampleBox: tiled = self.resize_tiled(im, dst_size, *tiles) assert_image_similar(reference, tiled, 0.01) + @pytest.mark.valgrind_known_error(reason="Known Failing") def test_subsample(self): # This test shows advantages of the subpixel resizing # after supersampling (e.g. during JPEG decoding). diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index c42310c32..6911ce460 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -88,6 +88,7 @@ def test_no_resize(): assert im.size == (64, 64) +@pytest.mark.valgrind_known_error(reason="Known Failing") def test_DCT_scaling_edges(): # Make an image with red borders and size (N * 8) + 1 to cross DCT grid im = Image.new("RGB", (257, 257), "red") diff --git a/depends/install_imagequant.sh b/depends/install_imagequant.sh index ed438f904..e204ea9ad 100755 --- a/depends/install_imagequant.sh +++ b/depends/install_imagequant.sh @@ -1,7 +1,7 @@ #!/bin/bash # install libimagequant -archive=libimagequant-2.13.1 +archive=libimagequant-2.14.0 ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz diff --git a/depends/install_webp.sh b/depends/install_webp.sh index 9b1882c43..568cb2df9 100755 --- a/depends/install_webp.sh +++ b/depends/install_webp.sh @@ -1,7 +1,7 @@ #!/bin/bash # install webp -archive=libwebp-1.1.0 +archive=libwebp-1.2.0 ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 44aa2a795..fd2f5620e 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -25,6 +25,14 @@ vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`). .. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/ +Tk/Tcl 8.4 +~~~~~~~~~~ + +.. deprecated:: 8.2.0 + +Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), +when Tk/Tcl 8.5 will be the minimum supported. + Image.show command parameter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/installation.rst b/docs/installation.rst index b358c18c4..4610d87d8 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -159,7 +159,7 @@ Many of Pillow's features require external libraries: * **littlecms** provides color management * Pillow version 2.2.1 and below uses liblcms1, Pillow 2.3.0 and - above uses liblcms2. Tested with **1.19** and **2.7-2.11**. + above uses liblcms2. Tested with **1.19** and **2.7-2.12**. * **libwebp** provides the WebP format. @@ -177,7 +177,7 @@ Many of Pillow's features require external libraries: * **libimagequant** provides improved color quantization - * Pillow has been tested with libimagequant **2.6-2.13.1** + * Pillow has been tested with libimagequant **2.6-2.14** * Libimagequant is licensed GPLv3, which is more restrictive than the Pillow license, therefore we will not be distributing binaries with libimagequant support enabled. @@ -465,9 +465,9 @@ These platforms have been reported to work at the versions mentioned. +----------------------------------+------------------------------+--------------------------------+-----------------------+ |**Operating system** |**Tested Python versions** |**Latest tested Pillow version**|**Tested processors** | +----------------------------------+------------------------------+--------------------------------+-----------------------+ -| macOS 11.0 Big Sur | 3.8, 3.9 | 8.0.1 |arm | +| macOS 11.0 Big Sur | 3.8, 3.9 | 8.1.0 |arm | | +------------------------------+--------------------------------+-----------------------+ -| | 3.6, 3.7, 3.8, 3.9 | 8.0.1 |x86-64 | +| | 3.6, 3.7, 3.8, 3.9 | 8.1.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | macOS 10.15 Catalina | 3.6, 3.7, 3.8, 3.9 | 8.0.1 |x86-64 | | +------------------------------+--------------------------------+ + diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 8d63c173b..f0a368479 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -22,7 +22,7 @@ Windows). .. code-block:: python from PIL import Image - im = Image.open("bride.jpg") + im = Image.open("hopper.jpg") im.rotate(45).show() Create thumbnails diff --git a/docs/reference/c_extension_debugging.rst b/docs/reference/c_extension_debugging.rst new file mode 100644 index 000000000..893acc699 --- /dev/null +++ b/docs/reference/c_extension_debugging.rst @@ -0,0 +1,469 @@ +C Extension debugging on Linux, with gbd/valgrind. +================================================== + +Install the tools +----------------- + +You need some basics in addition to the basic tools to build +pillow. These are what's required on Ubuntu, YMMV for other +distributions. + +- ``python3-dbg`` package for the gdb extensions and python symbols +- ``gdb`` and ``valgrind`` +- Potentially debug symbols for libraries. On ubuntu they're shipped + in package-dbgsym packages, from a different repo. + +:: + + deb http://ddebs.ubuntu.com focal main restricted universe multiverse + deb http://ddebs.ubuntu.com focal-updates main restricted universe multiverse + deb http://ddebs.ubuntu.com focal-proposed main restricted universe multiverse + +Then ``sudo apt-get update && sudo apt-get install libtiff5-dbgsym`` + +- There's a bug with the dbg package for at least python 3.8 on ubuntu + 20.04, and you need to add a new link or two to make it autoload when + running python: + +:: + + cd /usr/share/gdb/auto-load/usr/bin + ln -s python3.8m-gdb.py python3.8d-gdb.py + +- In Ubuntu 18.04, it's actually including the path to the virtualenv + in the search for the ``python3.*-gdb.py`` file, but you can + helpfully put in the same directory as the binary. + +- I also find that history is really useful for gdb, so I added this to + my ``~/.gdbinit`` file: + +:: + + set history filename ~/.gdb_history + set history save on + +- If the python stack isn't working in gdb, then + ``set debug auto-load`` can also be helpful in ``.gdbinit``. + +- Make a virtualenv with the debug python and activate it, then install + whatever dependencies are required and build. You want to build with + the debug python so you get symbols for your extension. + +:: + + virtualenv -p python3.8-dbg ~/vpy38-dbg + source ~/vpy38-dbg/bin/activate + cd ~/Pillow && pip install -r requirements.txt && make install + +Test Case +--------- + +Take your test image, and make a really simple harness. + +:: + + from PIL import Image + im = Image.open(path) + im.load() + +- Run this through valgrind, but note that python triggers some issues + on its own, so you're looking for items within the Pillow hierarchy + that don't look like they're solely in the python call chain. In this + example, the ones we're interested are after the warnings, and have + ``decode.c`` and ``TiffDecode.c`` in the call stack: + +:: + + (vpy38-dbg) ubuntu@primary:~/Home/tests$ valgrind python test_tiff.py + ==51890== Memcheck, a memory error detector + ==51890== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. + ==51890== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info + ==51890== Command: python test_tiff.py + ==51890== + ==51890== Invalid read of size 4 + ==51890== at 0x472E3D: address_in_range (obmalloc.c:1401) + ==51890== by 0x472EEA: pymalloc_free (obmalloc.c:1677) + ==51890== by 0x474960: _PyObject_Free (obmalloc.c:1896) + ==51890== by 0x473BAC: _PyMem_DebugRawFree (obmalloc.c:2187) + ==51890== by 0x473BD4: _PyMem_DebugFree (obmalloc.c:2318) + ==51890== by 0x474C08: PyObject_Free (obmalloc.c:709) + ==51890== by 0x45DD60: dictresize (dictobject.c:1259) + ==51890== by 0x45DD76: insertion_resize (dictobject.c:1019) + ==51890== by 0x464F30: PyDict_SetDefault (dictobject.c:2924) + ==51890== by 0x4D03BE: PyUnicode_InternInPlace (unicodeobject.c:15289) + ==51890== by 0x4D0700: PyUnicode_InternFromString (unicodeobject.c:15322) + ==51890== by 0x64D2FC: descr_new (descrobject.c:857) + ==51890== Address 0x4c1b020 is 384 bytes inside a block of size 1,160 free'd + ==51890== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) + ==51890== by 0x4735D3: _PyMem_RawFree (obmalloc.c:127) + ==51890== by 0x473BAC: _PyMem_DebugRawFree (obmalloc.c:2187) + ==51890== by 0x474941: PyMem_RawFree (obmalloc.c:595) + ==51890== by 0x47496E: _PyObject_Free (obmalloc.c:1898) + ==51890== by 0x473BAC: _PyMem_DebugRawFree (obmalloc.c:2187) + ==51890== by 0x473BD4: _PyMem_DebugFree (obmalloc.c:2318) + ==51890== by 0x474C08: PyObject_Free (obmalloc.c:709) + ==51890== by 0x45DD60: dictresize (dictobject.c:1259) + ==51890== by 0x45DD76: insertion_resize (dictobject.c:1019) + ==51890== by 0x464F30: PyDict_SetDefault (dictobject.c:2924) + ==51890== by 0x4D03BE: PyUnicode_InternInPlace (unicodeobject.c:15289) + ==51890== Block was alloc'd at + ==51890== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) + ==51890== by 0x473646: _PyMem_RawMalloc (obmalloc.c:99) + ==51890== by 0x473529: _PyMem_DebugRawAlloc (obmalloc.c:2120) + ==51890== by 0x473565: _PyMem_DebugRawMalloc (obmalloc.c:2153) + ==51890== by 0x4748B1: PyMem_RawMalloc (obmalloc.c:572) + ==51890== by 0x475909: _PyObject_Malloc (obmalloc.c:1628) + ==51890== by 0x473529: _PyMem_DebugRawAlloc (obmalloc.c:2120) + ==51890== by 0x473565: _PyMem_DebugRawMalloc (obmalloc.c:2153) + ==51890== by 0x4736B0: _PyMem_DebugMalloc (obmalloc.c:2303) + ==51890== by 0x474B78: PyObject_Malloc (obmalloc.c:685) + ==51890== by 0x45C435: new_keys_object (dictobject.c:558) + ==51890== by 0x45DA95: dictresize (dictobject.c:1202) + ==51890== + ==51890== Invalid read of size 4 + ==51890== at 0x472E3D: address_in_range (obmalloc.c:1401) + ==51890== by 0x47594A: pymalloc_realloc (obmalloc.c:1929) + ==51890== by 0x475A02: _PyObject_Realloc (obmalloc.c:1982) + ==51890== by 0x473DCA: _PyMem_DebugRawRealloc (obmalloc.c:2240) + ==51890== by 0x473FF8: _PyMem_DebugRealloc (obmalloc.c:2326) + ==51890== by 0x4749FB: PyMem_Realloc (obmalloc.c:623) + ==51890== by 0x44A6FC: list_resize (listobject.c:70) + ==51890== by 0x44A872: app1 (listobject.c:340) + ==51890== by 0x44FD65: PyList_Append (listobject.c:352) + ==51890== by 0x514315: r_ref (marshal.c:945) + ==51890== by 0x516034: r_object (marshal.c:1139) + ==51890== by 0x516C70: r_object (marshal.c:1389) + ==51890== Address 0x4c41020 is 32 bytes before a block of size 1,600 in arena "client" + ==51890== + ==51890== Conditional jump or move depends on uninitialised value(s) + ==51890== at 0x472E46: address_in_range (obmalloc.c:1403) + ==51890== by 0x47594A: pymalloc_realloc (obmalloc.c:1929) + ==51890== by 0x475A02: _PyObject_Realloc (obmalloc.c:1982) + ==51890== by 0x473DCA: _PyMem_DebugRawRealloc (obmalloc.c:2240) + ==51890== by 0x473FF8: _PyMem_DebugRealloc (obmalloc.c:2326) + ==51890== by 0x4749FB: PyMem_Realloc (obmalloc.c:623) + ==51890== by 0x44A6FC: list_resize (listobject.c:70) + ==51890== by 0x44A872: app1 (listobject.c:340) + ==51890== by 0x44FD65: PyList_Append (listobject.c:352) + ==51890== by 0x5E3321: _posix_listdir (posixmodule.c:3823) + ==51890== by 0x5E33A8: os_listdir_impl (posixmodule.c:3879) + ==51890== by 0x5E4D77: os_listdir (posixmodule.c.h:1197) + ==51890== + ==51890== Use of uninitialised value of size 8 + ==51890== at 0x472E59: address_in_range (obmalloc.c:1403) + ==51890== by 0x47594A: pymalloc_realloc (obmalloc.c:1929) + ==51890== by 0x475A02: _PyObject_Realloc (obmalloc.c:1982) + ==51890== by 0x473DCA: _PyMem_DebugRawRealloc (obmalloc.c:2240) + ==51890== by 0x473FF8: _PyMem_DebugRealloc (obmalloc.c:2326) + ==51890== by 0x4749FB: PyMem_Realloc (obmalloc.c:623) + ==51890== by 0x44A6FC: list_resize (listobject.c:70) + ==51890== by 0x44A872: app1 (listobject.c:340) + ==51890== by 0x44FD65: PyList_Append (listobject.c:352) + ==51890== by 0x5E3321: _posix_listdir (posixmodule.c:3823) + ==51890== by 0x5E33A8: os_listdir_impl (posixmodule.c:3879) + ==51890== by 0x5E4D77: os_listdir (posixmodule.c.h:1197) + ==51890== + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 16908288 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67895296 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 1572864 bytes but only got 0. Skipping tag 42 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 116647 bytes but only got 4867. Skipping tag 42738 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 3468830728 bytes but only got 4851. Skipping tag 279 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 2198732800 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67239937 bytes but only got 4125. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33947764 bytes but only got 0. Skipping tag 139 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 17170432 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 80478208 bytes but only got 0. Skipping tag 1 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 787460 bytes but only got 4882. Skipping tag 20 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 1075 bytes but only got 0. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 120586240 bytes but only got 0. Skipping tag 194 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 65536 bytes but only got 0. Skipping tag 3 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 198656 bytes but only got 0. Skipping tag 279 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 206848 bytes but only got 0. Skipping tag 64512 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 130968 bytes but only got 4882. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 77848 bytes but only got 4689. Skipping tag 64270 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 262156 bytes but only got 0. Skipping tag 257 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33624064 bytes but only got 0. Skipping tag 49152 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67178752 bytes but only got 4627. Skipping tag 50688 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33632768 bytes but only got 0. Skipping tag 56320 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 134386688 bytes but only got 4115. Skipping tag 2048 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33912832 bytes but only got 0. Skipping tag 7168 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 151966208 bytes but only got 4627. Skipping tag 10240 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 119032832 bytes but only got 3859. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 46535680 bytes but only got 0. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 35651584 bytes but only got 0. Skipping tag 42 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 524288 bytes but only got 0. Skipping tag 0 + warnings.warn( + _TIFFVSetField: tempfile.tif: Null count for "Tag 769" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 42754" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 769" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 42754" (type 1, writecount -3, passcount 1). + ZIPDecode: Decoding error at scanline 0, incorrect header check. + ==51890== Invalid write of size 4 + ==51890== at 0x61C39E6: putcontig8bitYCbCr22tile (tif_getimage.c:2146) + ==51890== by 0x61C5865: gtStripContig (tif_getimage.c:977) + ==51890== by 0x6094317: ReadStrip (TiffDecode.c:269) + ==51890== by 0x6094749: ImagingLibTiffDecode (TiffDecode.c:479) + ==51890== by 0x60615D1: _decode (decode.c:136) + ==51890== by 0x64BF47: method_vectorcall_VARARGS (descrobject.c:300) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x43627B: function_code_fastcall (call.c:283) + ==51890== by 0x436D21: _PyFunction_Vectorcall (call.c:410) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== Address 0x6f456d4 is 0 bytes after a block of size 68 alloc'd + ==51890== at 0x483DFAF: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) + ==51890== by 0x60946D0: ImagingLibTiffDecode (TiffDecode.c:469) + ==51890== by 0x60615D1: _decode (decode.c:136) + ==51890== by 0x64BF47: method_vectorcall_VARARGS (descrobject.c:300) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x43627B: function_code_fastcall (call.c:283) + ==51890== by 0x436D21: _PyFunction_Vectorcall (call.c:410) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x4DFDFB: _PyEval_EvalCodeWithName (ceval.c:4298) + ==51890== by 0x436C40: _PyFunction_Vectorcall (call.c:435) + ==51890== + ==51890== Invalid write of size 4 + ==51890== at 0x61C39B5: putcontig8bitYCbCr22tile (tif_getimage.c:2145) + ==51890== by 0x61C5865: gtStripContig (tif_getimage.c:977) + ==51890== by 0x6094317: ReadStrip (TiffDecode.c:269) + ==51890== by 0x6094749: ImagingLibTiffDecode (TiffDecode.c:479) + ==51890== by 0x60615D1: _decode (decode.c:136) + ==51890== by 0x64BF47: method_vectorcall_VARARGS (descrobject.c:300) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x43627B: function_code_fastcall (call.c:283) + ==51890== by 0x436D21: _PyFunction_Vectorcall (call.c:410) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== Address 0x6f456d8 is 4 bytes after a block of size 68 alloc'd + ==51890== at 0x483DFAF: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) + ==51890== by 0x60946D0: ImagingLibTiffDecode (TiffDecode.c:469) + ==51890== by 0x60615D1: _decode (decode.c:136) + ==51890== by 0x64BF47: method_vectorcall_VARARGS (descrobject.c:300) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x43627B: function_code_fastcall (call.c:283) + ==51890== by 0x436D21: _PyFunction_Vectorcall (call.c:410) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x4DFDFB: _PyEval_EvalCodeWithName (ceval.c:4298) + ==51890== by 0x436C40: _PyFunction_Vectorcall (call.c:435) + ==51890== + TIFFFillStrip: Invalid strip byte count 0, strip 1. + Traceback (most recent call last): + File "test_tiff.py", line 8, in + im.load() + File "/home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py", line 1087, in load + return self._load_libtiff() + File "/home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py", line 1191, in _load_libtiff + raise OSError(err) + OSError: -2 + sys:1: ResourceWarning: unclosed file <_io.BufferedReader name='crash-2020-10-test.tiff'> + ==51890== + ==51890== HEAP SUMMARY: + ==51890== in use at exit: 748,734 bytes in 444 blocks + ==51890== total heap usage: 6,320 allocs, 5,876 frees, 69,142,969 bytes allocated + ==51890== + ==51890== LEAK SUMMARY: + ==51890== definitely lost: 0 bytes in 0 blocks + ==51890== indirectly lost: 0 bytes in 0 blocks + ==51890== possibly lost: 721,538 bytes in 372 blocks + ==51890== still reachable: 27,196 bytes in 72 blocks + ==51890== suppressed: 0 bytes in 0 blocks + ==51890== Rerun with --leak-check=full to see details of leaked memory + ==51890== + ==51890== Use --track-origins=yes to see where uninitialised values come from + ==51890== For lists of detected and suppressed errors, rerun with: -s + ==51890== ERROR SUMMARY: 2556 errors from 6 contexts (suppressed: 0 from 0) + (vpy38-dbg) ubuntu@primary:~/Home/tests$ + +- Now that we've confirmed that there's something odd/bad going on, + it's time to gdb. +- Start with ``gdb python`` +- Set a break point starting with the valgrind stack trace. + ``b TiffDecode.c:269`` +- Run the script with ``r test_tiff.py`` +- When the break point is hit, explore the state with ``info locals``, + ``bt``, ``py-bt``, or ``p [variable]``. For pointers, + ``p *[variable]`` is useful. + +:: + + (vpy38-dbg) ubuntu@primary:~/Home/tests$ gdb python + GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2 + Copyright (C) 2020 Free Software Foundation, Inc. + License GPLv3+: GNU GPL version 3 or later + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + Type "show copying" and "show warranty" for details. + This GDB was configured as "x86_64-linux-gnu". + Type "show configuration" for configuration details. + For bug reporting instructions, please see: + . + Find the GDB manual and other documentation resources online at: + . + + For help, type "help". + Type "apropos word" to search for commands related to "word"... + Reading symbols from python... + (gdb) b TiffDecode.c:269 + No source file named TiffDecode.c. + Make breakpoint pending on future shared library load? (y or [n]) y + Breakpoint 1 (TiffDecode.c:269) pending. + (gdb) r test_tiff.py + Starting program: /home/ubuntu/vpy38-dbg/bin/python test_tiff.py + [Thread debugging using libthread_db enabled] + Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 16908288 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67895296 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 1572864 bytes but only got 0. Skipping tag 42 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 116647 bytes but only got 4867. Skipping tag 42738 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 3468830728 bytes but only got 4851. Skipping tag 279 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 2198732800 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67239937 bytes but only got 4125. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33947764 bytes but only got 0. Skipping tag 139 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 17170432 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 80478208 bytes but only got 0. Skipping tag 1 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 787460 bytes but only got 4882. Skipping tag 20 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 1075 bytes but only got 0. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 120586240 bytes but only got 0. Skipping tag 194 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 65536 bytes but only got 0. Skipping tag 3 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 198656 bytes but only got 0. Skipping tag 279 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 206848 bytes but only got 0. Skipping tag 64512 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 130968 bytes but only got 4882. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 77848 bytes but only got 4689. Skipping tag 64270 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 262156 bytes but only got 0. Skipping tag 257 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33624064 bytes but only got 0. Skipping tag 49152 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67178752 bytes but only got 4627. Skipping tag 50688 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33632768 bytes but only got 0. Skipping tag 56320 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 134386688 bytes but only got 4115. Skipping tag 2048 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33912832 bytes but only got 0. Skipping tag 7168 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 151966208 bytes but only got 4627. Skipping tag 10240 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 119032832 bytes but only got 3859. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 46535680 bytes but only got 0. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 35651584 bytes but only got 0. Skipping tag 42 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 524288 bytes but only got 0. Skipping tag 0 + warnings.warn( + _TIFFVSetField: tempfile.tif: Null count for "Tag 769" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 42754" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 769" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 42754" (type 1, writecount -3, passcount 1). + + Breakpoint 1, ReadStrip (tiff=tiff@entry=0xae9b90, row=0, buffer=0xac2eb0) at src/libImaging/TiffDecode.c:269 + 269 ok = TIFFRGBAImageGet(&img, buffer, img.width, rows_to_read); + (gdb) p img + $1 = {tif = 0xae9b90, stoponerr = 0, isContig = 1, alpha = 0, width = 20, height = 1536, bitspersample = 8, samplesperpixel = 3, + orientation = 1, req_orientation = 1, photometric = 6, redcmap = 0x0, greencmap = 0x0, bluecmap = 0x0, get = + 0x7ffff71d0710 , put = {any = 0x7ffff71ce550 , + contig = 0x7ffff71ce550 , separate = 0x7ffff71ce550 }, Map = 0x0, + BWmap = 0x0, PALmap = 0x0, ycbcr = 0xaf24b0, cielab = 0x0, UaToAa = 0x0, Bitdepth16To8 = 0x0, row_offset = 0, col_offset = 0} + (gdb) up + #1 0x00007ffff736174a in ImagingLibTiffDecode (im=0xac1f90, state=0x7ffff76767e0, buffer=, bytes=) + at src/libImaging/TiffDecode.c:479 + 479 if (ReadStrip(tiff, state->y, (UINT32 *)state->buffer) == -1) { + (gdb) p *state + $2 = {count = 0, state = 0, errcode = 0, x = 0, y = 0, ystep = 0, xsize = 17, ysize = 108, xoff = 0, yoff = 0, + shuffle = 0x7ffff735f411 , bits = 32, bytes = 68, buffer = 0xac2eb0 "P\354\336\367\377\177", context = 0xa75440, fd = 0x0} + (gdb) py-bt + Traceback (most recent call first): + File "/home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py", line 1428, in _load_libtiff + + File "/home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py", line 1087, in load + return self._load_libtiff() + File "test_tiff.py", line 8, in + im.load() + +- Poke around till you understand what's going on. In this case, + state->xsize and img.width are different, which led to an out of + bounds write, as the receiving buffer was sized for the smaller of + the two. + +Caveats +------- + +- If your program is running/hung in a docker container and your host + has the appropriate tools, you can run gdb as the superuser in the + host and you may be able to get a trace of where the process is hung. + You probably won't have the capability to do that from within the + docker container, as the trace capacity isn't allowed by default. + +- Variations of this are possible on the mac/windows, but the details + are going to be different. + +- IIRC, Fedora has the gdb bits working by default. Ubuntu has always + been a bit of a battle to make it work. diff --git a/docs/reference/features.rst b/docs/reference/features.rst index dd218fa0e..0a6381098 100644 --- a/docs/reference/features.rst +++ b/docs/reference/features.rst @@ -17,7 +17,7 @@ Modules Support for the following modules can be checked: * ``pil``: The Pillow core module, required for all functionality. -* ``tkinter``: Tkinter support. Version number not available. +* ``tkinter``: Tkinter support. * ``freetype2``: FreeType font support via :py:func:`PIL.ImageFont.truetype`. * ``littlecms2``: LittleCMS 2 support via :py:mod:`PIL.ImageCms`. * ``webp``: WebP image support. diff --git a/docs/reference/internal_design.rst b/docs/reference/internal_design.rst index 5f911db51..2e2d3322f 100644 --- a/docs/reference/internal_design.rst +++ b/docs/reference/internal_design.rst @@ -8,3 +8,4 @@ Internal Reference Docs limits block_allocator internal_modules + c_extension_debugging diff --git a/docs/releasenotes/8.1.0.rst b/docs/releasenotes/8.1.0.rst index 90847af81..5c4ee3773 100644 --- a/docs/releasenotes/8.1.0.rst +++ b/docs/releasenotes/8.1.0.rst @@ -69,6 +69,9 @@ Dependencies OpenJPEG in the macOS and Linux wheels has been updated from 2.3.1 to 2.4.0, including security fixes. +LibTIFF in the macOS and Linux wheels has been updated from 4.1.0 to 4.2.0, including +security fixes discovered by fuzzers. + Other Changes ============= diff --git a/docs/releasenotes/8.2.0.rst b/docs/releasenotes/8.2.0.rst new file mode 100644 index 000000000..8ddbc7f54 --- /dev/null +++ b/docs/releasenotes/8.2.0.rst @@ -0,0 +1,40 @@ +8.2.0 +----- + +Deprecations +============ + +Tk/Tcl 8.4 +^^^^^^^^^^ + +Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), +when Tk/Tcl 8.5 will be the minimum supported. + +API Changes +=========== + +TODO +^^^^ + +TODO + +API Additions +============= + +TODO +^^^^ + +TODO + +Security +======== + +TODO + +Other Changes +============= + +TODO +^^^^ + +TODO diff --git a/docs/releasenotes/index.rst b/docs/releasenotes/index.rst index cd73de814..0930768e7 100644 --- a/docs/releasenotes/index.rst +++ b/docs/releasenotes/index.rst @@ -14,6 +14,7 @@ expected to be backported to earlier versions. .. toctree:: :maxdepth: 2 + 8.2.0 8.1.0 8.0.1 8.0.0 diff --git a/docs/releasenotes/versioning.rst b/docs/releasenotes/versioning.rst index 1653bff3c..a8c9fc998 100644 --- a/docs/releasenotes/versioning.rst +++ b/docs/releasenotes/versioning.rst @@ -3,7 +3,7 @@ Versioning ========== -Pillow follows [Semantic Versioning](https://semver.org/): +Pillow follows `Semantic Versioning `_: Given a version number MAJOR.MINOR.PATCH, increment the: diff --git a/selftest.py b/selftest.py index a9a02ef71..7e08d183b 100755 --- a/selftest.py +++ b/selftest.py @@ -147,9 +147,7 @@ def testimage(): ('F', (128, 128)) PIL can do many other things, but I'll leave that for another - day. If you're curious, check the handbook, available from: - - http://www.pythonware.com + day. Cheers /F """ diff --git a/setup.py b/setup.py index fbf869ffb..cc902c152 100755 --- a/setup.py +++ b/setup.py @@ -37,7 +37,7 @@ JPEG_ROOT = None LCMS_ROOT = None TIFF_ROOT = None ZLIB_ROOT = None - +FUZZING_BUILD = "LIB_FUZZING_ENGINE" in os.environ if sys.platform == "win32" and sys.version_info >= (3, 10): import atexit @@ -394,6 +394,9 @@ class pil_build_ext(build_ext): extension.define_macros += define_macros if sources is not None: extension.sources += sources + if FUZZING_BUILD: + extension.language = "c++" + extension.extra_link_args = ["--stdlib=libc++"] break def _remove_extension(self, name): @@ -940,7 +943,7 @@ class pil_build_ext(build_ext): def debug_build(): - return hasattr(sys, "gettotalrefcount") + return hasattr(sys, "gettotalrefcount") or FUZZING_BUILD files = ["src/_imaging.c"] diff --git a/src/PIL/Image.py b/src/PIL/Image.py index e2540a2b2..e6d3adcf7 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -586,10 +586,10 @@ class Image: This operation will destroy the image core and release its memory. The image data will be unusable afterward. - This function is only required to close images that have not - had their file read and closed by the - :py:meth:`~PIL.Image.Image.load` method. See - :ref:`file-handling` for more information. + This function is required to close images that have multiple frames or + have not had their file read and closed by the + :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for + more information. """ try: if hasattr(self, "_close__fp"): @@ -878,7 +878,7 @@ class Image: The default method of converting a greyscale ("L") or "RGB" image into a bilevel (mode "1") image uses Floyd-Steinberg dither to approximate the original image luminosity levels. If - dither is :data:`NONE`, all values larger than 128 are set to 255 (white), + dither is :data:`NONE`, all values larger than 127 are set to 255 (white), all other values to 0 (black). To use other thresholds, use the :py:meth:`~PIL.Image.Image.point` method. @@ -1243,6 +1243,10 @@ class Image: """ Returns a list of colors used in this image. + The colors will be in the image's mode. For example, an RGB image will + return a tuple of (red, green, blue) color values, and a P image will + return the index of the color in the palette. + :param maxcolors: Maximum number of colors. If this number is exceeded, this method returns None. The default limit is 256 colors. diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py index a24d44b42..3874e5436 100644 --- a/src/PIL/PcxImagePlugin.py +++ b/src/PIL/PcxImagePlugin.py @@ -111,7 +111,7 @@ class PcxImageFile(ImageFile.ImageFile): self._size = bbox[2] - bbox[0], bbox[3] - bbox[1] # don't trust the passed in stride. Calculate for ourselves. - # CVE-2020-35655 + # CVE-2020-35653 stride = (self._size[0] * bits + 7) // 8 stride += stride % 2 diff --git a/src/PIL/_tkinter_finder.py b/src/PIL/_tkinter_finder.py index 7018a1b79..58aeffbfb 100644 --- a/src/PIL/_tkinter_finder.py +++ b/src/PIL/_tkinter_finder.py @@ -1,9 +1,20 @@ """ Find compiled module linking to Tcl / Tk libraries """ import sys +import tkinter +import warnings from tkinter import _tkinter as tk if hasattr(sys, "pypy_find_executable"): TKINTER_LIB = tk.tklib_cffi.__file__ else: TKINTER_LIB = tk.__file__ + +tk_version = str(tkinter.TkVersion) +if tk_version == "8.4": + warnings.warn( + "Support for Tk/Tcl 8.4 is deprecated and will be removed" + " in Pillow 10 (2023-01-02). Please upgrade to Tk/Tcl 8.5 " + "or newer.", + DeprecationWarning, + ) diff --git a/src/PIL/features.py b/src/PIL/features.py index 85459063b..66d0ba10a 100644 --- a/src/PIL/features.py +++ b/src/PIL/features.py @@ -9,7 +9,7 @@ from . import Image modules = { "pil": ("PIL._imaging", "PILLOW_VERSION"), - "tkinter": ("PIL._tkinter_finder", None), + "tkinter": ("PIL._tkinter_finder", "tk_version"), "freetype2": ("PIL._imagingft", "freetype2_version"), "littlecms2": ("PIL._imagingcms", "littlecms_version"), "webp": ("PIL._webp", "webpdecoder_version"), diff --git a/src/_imaging.c b/src/_imaging.c index a8741f6ad..01dd22486 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -4134,8 +4134,9 @@ setup_module(PyObject *m) { } #endif + PyObject *have_libjpegturbo; #ifdef LIBJPEG_TURBO_VERSION - PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_True); + have_libjpegturbo = Py_True; #define tostr1(a) #a #define tostr(a) tostr1(a) PyDict_SetItemString( @@ -4143,19 +4144,24 @@ setup_module(PyObject *m) { #undef tostr #undef tostr1 #else - PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_False); + have_libjpegturbo = Py_False; #endif + Py_INCREF(have_libjpegturbo); + PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", have_libjpegturbo); + PyObject *have_libimagequant; #ifdef HAVE_LIBIMAGEQUANT - PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", Py_True); + have_libimagequant = Py_True; { extern const char *ImagingImageQuantVersion(void); PyDict_SetItemString( d, "imagequant_version", PyUnicode_FromString(ImagingImageQuantVersion())); } #else - PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", Py_False); + have_libimagequant = Py_False; #endif + Py_INCREF(have_libimagequant); + PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", have_libimagequant); #ifdef HAVE_LIBZ /* zip encoding strategies */ @@ -4189,11 +4195,14 @@ setup_module(PyObject *m) { } #endif + PyObject *have_xcb; #ifdef HAVE_XCB - PyModule_AddObject(m, "HAVE_XCB", Py_True); + have_xcb = Py_True; #else - PyModule_AddObject(m, "HAVE_XCB", Py_False); + have_xcb = Py_False; #endif + Py_INCREF(have_xcb); + PyModule_AddObject(m, "HAVE_XCB", have_xcb); PyDict_SetItemString(d, "PILLOW_VERSION", PyUnicode_FromString(version)); diff --git a/src/_webp.c b/src/_webp.c index c7875fa36..4d51d99df 100644 --- a/src/_webp.c +++ b/src/_webp.c @@ -920,20 +920,26 @@ static PyMethodDef webpMethods[] = { void addMuxFlagToModule(PyObject *m) { + PyObject *have_webpmux; #ifdef HAVE_WEBPMUX - PyModule_AddObject(m, "HAVE_WEBPMUX", Py_True); + have_webpmux = Py_True; #else - PyModule_AddObject(m, "HAVE_WEBPMUX", Py_False); + have_webpmux = Py_False; #endif + Py_INCREF(have_webpmux); + PyModule_AddObject(m, "HAVE_WEBPMUX", have_webpmux); } void addAnimFlagToModule(PyObject *m) { + PyObject *have_webpanim; #ifdef HAVE_WEBPANIM - PyModule_AddObject(m, "HAVE_WEBPANIM", Py_True); + have_webpanim = Py_True; #else - PyModule_AddObject(m, "HAVE_WEBPANIM", Py_False); + have_webpanim = Py_False; #endif + Py_INCREF(have_webpanim); + PyModule_AddObject(m, "HAVE_WEBPANIM", have_webpanim); } void diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index 3b1a15eac..4ab83b7eb 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -154,9 +154,9 @@ deps = { # "bins": [r"libtiff\*.dll"], }, "libwebp": { - "url": "http://downloads.webmproject.org/releases/webp/libwebp-1.1.0.tar.gz", - "filename": "libwebp-1.1.0.tar.gz", - "dir": "libwebp-1.1.0", + "url": "http://downloads.webmproject.org/releases/webp/libwebp-1.2.0.tar.gz", + "filename": "libwebp-1.2.0.tar.gz", + "dir": "libwebp-1.2.0", "build": [ cmd_rmdir(r"output\release-static"), # clean cmd_nmake( @@ -219,9 +219,9 @@ deps = { # "bins": [r"objs\{msbuild_arch}\Release\freetype.dll"], }, "lcms2": { - "url": SF_MIRROR + "/project/lcms/lcms/2.11/lcms2-2.11.tar.gz", - "filename": "lcms2-2.11.tar.gz", - "dir": "lcms2-2.11", + "url": SF_MIRROR + "/project/lcms/lcms/2.12/lcms2-2.12.tar.gz", + "filename": "lcms2-2.12.tar.gz", + "dir": "lcms2-2.12", "patch": { r"Projects\VC2017\lcms2_static\lcms2_static.vcxproj": { # default is /MD for x86 and /MT for x64, we need /MD always