mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-25 00:00:34 +03:00
Certain corrupted jpegs can result in no data read
On truncated jpeg, decoder can suspend waiting for additional bytes in buffer. For some input files, decoder suspends on jpeg_start_decompress stage. If at this point file reader reaches EOF, py code never gets back to jpeg decoder and we end up with no bytes to result image. This leaves us with some amount of potentially useful bytes undecoded and thrown away. Libjpeg docs suggest that in such situation, more appropriate would be to add EOI marker to the end of buffer, which will allows decoder to finish. https://github.com/libjpeg-turbo/libjpeg-turbo/blob/0dd9a2c1fd6c/libjpeg.txt#L1803-L1809 Docs also mention that adding EOI markers is what non-suspending code does anyway.
This commit is contained in:
parent
1591c530bd
commit
add2746ac6
|
@ -202,44 +202,39 @@ class ImageFile(Image.Image):
|
|||
for decoder_name, extents, offset, args in self.tile:
|
||||
decoder = Image._getdecoder(self.mode, decoder_name,
|
||||
args, self.decoderconfig)
|
||||
seek(offset)
|
||||
decoder.setimage(self.im, extents)
|
||||
if decoder.pulls_fd:
|
||||
decoder.setfd(self.fp)
|
||||
status, err_code = decoder.decode(b"")
|
||||
else:
|
||||
b = prefix
|
||||
while True:
|
||||
try:
|
||||
s = read(self.decodermaxblock)
|
||||
except (IndexError, struct.error): # truncated png/gif
|
||||
if LOAD_TRUNCATED_IMAGES:
|
||||
try:
|
||||
seek(offset)
|
||||
decoder.setimage(self.im, extents)
|
||||
if decoder.pulls_fd:
|
||||
decoder.setfd(self.fp)
|
||||
status, err_code = decoder.decode(b"")
|
||||
else:
|
||||
b = prefix
|
||||
while True:
|
||||
try:
|
||||
s = read(self.decodermaxblock)
|
||||
except (IndexError, struct.error): # truncated png/gif
|
||||
if LOAD_TRUNCATED_IMAGES:
|
||||
break
|
||||
else:
|
||||
raise IOError("image file is truncated")
|
||||
|
||||
if not s: # truncated jpeg
|
||||
if LOAD_TRUNCATED_IMAGES:
|
||||
s = b"\xFF\xD9" # Pretend file is finished adding EOI marker
|
||||
else:
|
||||
self.tile = []
|
||||
raise IOError("image file is truncated "
|
||||
"(%d bytes not processed)" % len(b))
|
||||
|
||||
b = b + s
|
||||
n, err_code = decoder.decode(b)
|
||||
if n < 0:
|
||||
break
|
||||
else:
|
||||
raise IOError("image file is truncated")
|
||||
|
||||
if not s: # truncated jpeg
|
||||
self.tile = []
|
||||
|
||||
# JpegDecode needs to clean things up here either way
|
||||
# If we don't destroy the decompressor,
|
||||
# we have a memory leak.
|
||||
decoder.cleanup()
|
||||
|
||||
if LOAD_TRUNCATED_IMAGES:
|
||||
break
|
||||
else:
|
||||
raise IOError("image file is truncated "
|
||||
"(%d bytes not processed)" % len(b))
|
||||
|
||||
b = b + s
|
||||
n, err_code = decoder.decode(b)
|
||||
if n < 0:
|
||||
break
|
||||
b = b[n:]
|
||||
|
||||
# Need to cleanup here to prevent leaks in PyPy
|
||||
decoder.cleanup()
|
||||
b = b[n:]
|
||||
finally:
|
||||
# Need to cleanup here to prevent leaks
|
||||
decoder.cleanup()
|
||||
|
||||
self.tile = []
|
||||
self.readonly = readonly
|
||||
|
|
Loading…
Reference in New Issue
Block a user