diff --git a/Tests/images/timeout-6646305047838720 b/Tests/images/timeout-6646305047838720 new file mode 100644 index 00000000000..eae1f333a03 Binary files /dev/null and b/Tests/images/timeout-6646305047838720 differ diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 072f7d4013b..5801e176636 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -3,7 +3,7 @@ import pytest -from PIL import Image, TiffImagePlugin +from PIL import Image, ImageFile, TiffImagePlugin from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION from .helper import ( @@ -726,6 +726,14 @@ def test_string_dimension(self): with pytest.raises(OSError): im.load() + @pytest.mark.timeout(6) + @pytest.mark.filterwarnings("ignore:Truncated File Read") + def test_timeout(self): + with Image.open("Tests/images/timeout-6646305047838720") as im: + ImageFile.LOAD_TRUNCATED_IMAGES = True + im.load() + ImageFile.LOAD_TRUNCATED_IMAGES = False + @pytest.mark.skipif(not is_win32(), reason="Windows only") class TestFileTiffW32: diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index d43667ca0c7..3374a5b1dae 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -28,6 +28,7 @@ # import io +import itertools import struct import sys @@ -210,6 +211,13 @@ def load(self): except AttributeError: prefix = b"" + # Remove consecutive duplicates that only differ by their offset + self.tile = [ + list(tiles)[-1] + for _, tiles in itertools.groupby( + self.tile, lambda tile: (tile[0], tile[1], tile[3]) + ) + ] for decoder_name, extents, offset, args in self.tile: decoder = Image._getdecoder( self.mode, decoder_name, args, self.decoderconfig