mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 01:04:29 +03:00
Merge pull request #2541 from uploadcare/fix-truncated-png-loading
Fix truncated png loading
This commit is contained in:
commit
5a671830d8
|
@ -113,7 +113,8 @@ class ChunkStream(object):
|
||||||
length = i32(s)
|
length = i32(s)
|
||||||
|
|
||||||
if not is_cid(cid):
|
if not is_cid(cid):
|
||||||
raise SyntaxError("broken PNG file (chunk %s)" % repr(cid))
|
if not ImageFile.LOAD_TRUNCATED_IMAGES:
|
||||||
|
raise SyntaxError("broken PNG file (chunk %s)" % repr(cid))
|
||||||
|
|
||||||
return cid, pos, length
|
return cid, pos, length
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
from helper import unittest, PillowTestCase, hopper
|
from helper import unittest, PillowTestCase, hopper
|
||||||
|
from PIL import Image, ImageFile, PngImagePlugin
|
||||||
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from PIL import Image
|
|
||||||
from PIL import ImageFile
|
|
||||||
from PIL import PngImagePlugin
|
|
||||||
import zlib
|
import zlib
|
||||||
|
import sys
|
||||||
|
|
||||||
codecs = dir(Image.core)
|
codecs = dir(Image.core)
|
||||||
|
|
||||||
|
# For Truncated phng memory leak
|
||||||
|
MEM_LIMIT = 1 # max increase in MB
|
||||||
|
ITERATIONS = 100
|
||||||
|
|
||||||
# sample png stream
|
# sample png stream
|
||||||
|
|
||||||
TEST_PNG_FILE = "Tests/images/hopper.png"
|
TEST_PNG_FILE = "Tests/images/hopper.png"
|
||||||
|
@ -530,5 +532,33 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assertLess(chunks.index(b"pHYs"), chunks.index(b"IDAT"))
|
self.assertLess(chunks.index(b"pHYs"), chunks.index(b"IDAT"))
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS")
|
||||||
|
class TestTruncatedPngPLeaks(PillowTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
if "zip_encoder" not in codecs or "zip_decoder" not in codecs:
|
||||||
|
self.skipTest("zip/deflate support not available")
|
||||||
|
|
||||||
|
def _get_mem_usage(self):
|
||||||
|
from resource import getpagesize, getrusage, RUSAGE_SELF
|
||||||
|
mem = getrusage(RUSAGE_SELF).ru_maxrss
|
||||||
|
return mem * getpagesize() / 1024 / 1024
|
||||||
|
|
||||||
|
def test_leak_load(self):
|
||||||
|
with open('Tests/images/hopper.png', 'rb') as f:
|
||||||
|
DATA = BytesIO(f.read(16 * 1024))
|
||||||
|
|
||||||
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||||
|
start_mem = self._get_mem_usage()
|
||||||
|
try:
|
||||||
|
for _ in range(ITERATIONS):
|
||||||
|
with Image.open(DATA) as im:
|
||||||
|
im.load()
|
||||||
|
mem = (self._get_mem_usage() - start_mem)
|
||||||
|
self.assertLess(mem, MEM_LIMIT, msg='memory usage limit exceeded')
|
||||||
|
finally:
|
||||||
|
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
1
decode.c
1
decode.c
|
@ -779,6 +779,7 @@ PyImaging_ZipDecoderNew(PyObject* self, PyObject* args)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
decoder->decode = ImagingZipDecode;
|
decoder->decode = ImagingZipDecode;
|
||||||
|
decoder->cleanup = ImagingZipDecodeCleanup;
|
||||||
|
|
||||||
((ZIPSTATE*)decoder->state.context)->interlaced = interlaced;
|
((ZIPSTATE*)decoder->state.context)->interlaced = interlaced;
|
||||||
|
|
||||||
|
|
|
@ -455,6 +455,7 @@ extern int ImagingXbmEncode(Imaging im, ImagingCodecState state,
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
extern int ImagingZipDecode(Imaging im, ImagingCodecState state,
|
extern int ImagingZipDecode(Imaging im, ImagingCodecState state,
|
||||||
UINT8* buffer, int bytes);
|
UINT8* buffer, int bytes);
|
||||||
|
extern int ImagingZipDecodeCleanup(ImagingCodecState state);
|
||||||
extern int ImagingZipEncode(Imaging im, ImagingCodecState state,
|
extern int ImagingZipEncode(Imaging im, ImagingCodecState state,
|
||||||
UINT8* buffer, int bytes);
|
UINT8* buffer, int bytes);
|
||||||
extern int ImagingZipEncodeCleanup(ImagingCodecState state);
|
extern int ImagingZipEncodeCleanup(ImagingCodecState state);
|
||||||
|
|
|
@ -85,6 +85,8 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
err = inflateInit(&context->z_stream);
|
err = inflateInit(&context->z_stream);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
state->errcode = IMAGING_CODEC_CONFIG;
|
state->errcode = IMAGING_CODEC_CONFIG;
|
||||||
|
free(context->previous);
|
||||||
|
context->previous = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +128,7 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
else
|
else
|
||||||
state->errcode = IMAGING_CODEC_CONFIG;
|
state->errcode = IMAGING_CODEC_CONFIG;
|
||||||
free(context->previous);
|
free(context->previous);
|
||||||
|
context->previous = NULL;
|
||||||
inflateEnd(&context->z_stream);
|
inflateEnd(&context->z_stream);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -191,6 +194,7 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
default:
|
default:
|
||||||
state->errcode = IMAGING_CODEC_UNKNOWN;
|
state->errcode = IMAGING_CODEC_UNKNOWN;
|
||||||
free(context->previous);
|
free(context->previous);
|
||||||
|
context->previous = NULL;
|
||||||
inflateEnd(&context->z_stream);
|
inflateEnd(&context->z_stream);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -258,6 +262,7 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
state->errcode = IMAGING_CODEC_BROKEN; */
|
state->errcode = IMAGING_CODEC_BROKEN; */
|
||||||
|
|
||||||
free(context->previous);
|
free(context->previous);
|
||||||
|
context->previous = NULL;
|
||||||
inflateEnd(&context->z_stream);
|
inflateEnd(&context->z_stream);
|
||||||
return -1; /* end of file (errcode=0) */
|
return -1; /* end of file (errcode=0) */
|
||||||
|
|
||||||
|
@ -274,4 +279,20 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ImagingZipDecodeCleanup(ImagingCodecState state){
|
||||||
|
/* called to free the decompression engine when the decode terminates
|
||||||
|
due to a corrupt or truncated image
|
||||||
|
*/
|
||||||
|
ZIPSTATE* context = (ZIPSTATE*) state->context;
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
if (context->previous) {
|
||||||
|
inflateEnd(&context->z_stream);
|
||||||
|
free(context->previous);
|
||||||
|
context->previous = NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user