diff --git a/PIL/PngImagePlugin.py b/PIL/PngImagePlugin.py index d6778821b..87847eebd 100644 --- a/PIL/PngImagePlugin.py +++ b/PIL/PngImagePlugin.py @@ -36,6 +36,7 @@ from __future__ import print_function import logging import re import zlib +import struct from PIL import Image, ImageFile, ImagePalette, _binary @@ -106,17 +107,20 @@ class ChunkStream(object): def read(self): "Fetch a new chunk. Returns header information." - - if self.queue: - cid, pos, length = self.queue[-1] - del self.queue[-1] - self.fp.seek(pos) - else: - s = self.fp.read(8) - cid = s[4:] - pos = self.fp.tell() - length = i32(s) - + cid = None + try: + if self.queue: + cid, pos, length = self.queue[-1] + del self.queue[-1] + self.fp.seek(pos) + else: + s = self.fp.read(8) + cid = s[4:] + pos = self.fp.tell() + length = i32(s) + except struct.error: + SyntaxError("truncated PNG file (chunk %s)" % repr(cid)) + if not is_cid(cid): raise SyntaxError("broken PNG file (chunk %s)" % repr(cid)) @@ -138,11 +142,15 @@ class ChunkStream(object): def crc(self, cid, data): "Read and verify checksum" - crc1 = Image.core.crc32(data, Image.core.crc32(cid)) - crc2 = i16(self.fp.read(2)), i16(self.fp.read(2)) - if crc1 != crc2: - raise SyntaxError("broken PNG file" - "(bad header checksum in %s)" % cid) + try: + crc1 = Image.core.crc32(data, Image.core.crc32(cid)) + crc2 = i16(self.fp.read(2)), i16(self.fp.read(2)) + if crc1 != crc2: + raise SyntaxError("broken PNG file (bad header checksum in %s)" + % cid) + except struct.error: + raise SyntaxError("broken PNG file (incomplete checksum in %s)" + % cid) def crc_skip(self, cid, data): "Read checksum. Used if the C module is not present" diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index cb72b2d73..63ec8a303 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -253,6 +253,22 @@ class TestFilePng(PillowTestCase): im.load() self.assertRaises(RuntimeError, im.verify) + def test_verify_struct_error(self): + # Check open/load/verify exception (#1755) + + # offsets to test, -10: breaks in i32() in read. + # -13: breaks in crc, txt chunk. + # -14: malformed chunk + + for offset in (-10, -13, -14): + with open(TEST_PNG_FILE,'rb') as f: + test_file = f.read()[:offset] + + im = Image.open(BytesIO(test_file)) + self.assertTrue(im.fp is not None) + self.assertRaises(SyntaxError, im.verify) + + def test_roundtrip_dpi(self): # Check dpi roundtripping