Merge pull request #2974 from wiredfool/webp_leak

Fix memory leak when opening webp files
This commit is contained in:
Hugo 2018-01-25 10:51:23 +02:00 committed by GitHub
commit 797d67b9a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 39 deletions

View File

@ -1,38 +0,0 @@
from __future__ import division
from helper import unittest, PillowTestCase
import sys
from PIL import Image
from io import BytesIO
# Limits for testing the leak
mem_limit = 16 # max increase in MB
iterations = 5000
test_file = "Tests/images/hopper.webp"
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS")
class TestWebPLeaks(PillowTestCase):
def setUp(self):
try:
from PIL import _webp
except ImportError:
self.skipTest('WebP support not installed')
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(test_file, 'rb') as f:
im_data = f.read()
start_mem = self._get_mem_usage()
for _ in range(iterations):
with Image.open(BytesIO(im_data)) as im:
im.load()
mem = (self._get_mem_usage() - start_mem)
self.assertLess(mem, mem_limit, msg='memory usage limit exceeded')
if __name__ == '__main__':
unittest.main()

25
Tests/test_webp_leaks.py Normal file
View File

@ -0,0 +1,25 @@
from helper import unittest, PillowLeakTestCase
from PIL import Image, features
from io import BytesIO
test_file = "Tests/images/hopper.webp"
@unittest.skipUnless(features.check('webp'), "WebP is not installed")
class TestWebPLeaks(PillowLeakTestCase):
mem_limit = 3 * 1024 # kb
iterations = 100
def test_leak_load(self):
with open(test_file, 'rb') as f:
im_data = f.read()
def core():
with Image.open(BytesIO(im_data)) as im:
im.load()
self._test_leak(core)
if __name__ == '__main__':
unittest.main()

View File

@ -410,6 +410,7 @@ PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args)
uint8_t* buf;
int timestamp;
PyObject* bytes;
PyObject* ret;
WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self;
if (!WebPAnimDecoderGetNext(decp->dec, &buf, &timestamp)) {
@ -419,7 +420,11 @@ PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args)
bytes = PyBytes_FromStringAndSize((char *)buf,
decp->info.canvas_width * 4 * decp->info.canvas_height);
return Py_BuildValue("Si", bytes, timestamp);
ret = Py_BuildValue("Si", bytes, timestamp);
Py_DECREF(bytes);
return ret;
}
PyObject* _anim_decoder_has_more_frames(PyObject* self, PyObject* args)