mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-25 00:34:14 +03:00
Merge branch 'master' into fribidi-link
This commit is contained in:
commit
9b56833300
|
@ -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?
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
6
.github/workflows/lint.yml
vendored
6
.github/workflows/lint.yml
vendored
|
@ -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
|
||||
|
|
2
.github/workflows/test-docker.yml
vendored
2
.github/workflows/test-docker.yml
vendored
|
@ -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"
|
||||
|
|
5
.github/workflows/test-windows.yml
vendored
5
.github/workflows/test-windows.yml
vendored
|
@ -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
|
||||
|
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
@ -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')
|
||||
|
|
18
CHANGES.rst
18
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)
|
||||
------------------
|
||||
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
|
|
48
Tests/oss-fuzz/fuzz_pillow.py
Normal file
48
Tests/oss-fuzz/fuzz_pillow.py
Normal file
|
@ -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()
|
|
@ -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:
|
||||
|
|
|
@ -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] == {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -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 |
|
||||
| +------------------------------+--------------------------------+ +
|
||||
|
|
|
@ -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
|
||||
|
|
469
docs/reference/c_extension_debugging.rst
Normal file
469
docs/reference/c_extension_debugging.rst
Normal file
|
@ -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 <module>
|
||||
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 <http://gnu.org/licenses/gpl.html>
|
||||
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:
|
||||
<http://www.gnu.org/software/gdb/bugs/>.
|
||||
Find the GDB manual and other documentation resources online at:
|
||||
<http://www.gnu.org/software/gdb/documentation/>.
|
||||
|
||||
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 <gtStripContig>, put = {any = 0x7ffff71ce550 <putcontig8bitYCbCr22tile>,
|
||||
contig = 0x7ffff71ce550 <putcontig8bitYCbCr22tile>, separate = 0x7ffff71ce550 <putcontig8bitYCbCr22tile>}, 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=<optimized out>, bytes=<optimized out>)
|
||||
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 <copy4>, 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 <module>
|
||||
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.
|
|
@ -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.
|
||||
|
|
|
@ -8,3 +8,4 @@ Internal Reference Docs
|
|||
limits
|
||||
block_allocator
|
||||
internal_modules
|
||||
c_extension_debugging
|
||||
|
|
|
@ -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
|
||||
=============
|
||||
|
||||
|
|
40
docs/releasenotes/8.2.0.rst
Normal file
40
docs/releasenotes/8.2.0.rst
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Versioning
|
||||
==========
|
||||
|
||||
Pillow follows [Semantic Versioning](https://semver.org/):
|
||||
Pillow follows `Semantic Versioning <https://semver.org/>`_:
|
||||
|
||||
Given a version number MAJOR.MINOR.PATCH, increment the:
|
||||
|
||||
|
|
|
@ -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
|
||||
"""
|
||||
|
|
7
setup.py
7
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"]
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
14
src/_webp.c
14
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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user