From 4f6c366e751e1e43fa82c0ffb70e5b7b42f9858d Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Thu, 16 Apr 2015 16:27:57 +0200 Subject: [PATCH 1/2] fix imaging leaks in putdata and getlist --- Tests/check_imaging_leaks.py | 43 ++++++++++++++++++++++++++++++++++++ _imaging.c | 6 ++++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 Tests/check_imaging_leaks.py diff --git a/Tests/check_imaging_leaks.py b/Tests/check_imaging_leaks.py new file mode 100644 index 000000000..3a7dcaa2b --- /dev/null +++ b/Tests/check_imaging_leaks.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +from __future__ import division +from helper import unittest, PillowTestCase +import sys +from PIL import Image, ImageFilter + +min_iterations = 100 +max_iterations = 10000 + +@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS") +class TestImagingLeaks(PillowTestCase): + + 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(self, min_iterations, max_iterations, fn, *args, **kwargs): + mem_limit = None + for i in range(max_iterations): + fn(*args, **kwargs) + mem = self._get_mem_usage() + if i < min_iterations: + mem_limit = mem + 1 + continue + self.assertLessEqual(mem, mem_limit, + msg='memory usage limit exceeded after %d iterations' + % (i + 1)) + + def test_leak_putdata(self): + im = Image.new('RGB', (25, 25)) + self._test_leak(min_iterations, max_iterations, im.putdata, im.getdata()) + + def test_leak_getlist(self): + im = Image.new('P', (25, 25)) + self._test_leak(min_iterations, max_iterations, + # Pass a new list at each iteration. + lambda: im.point(range(256))) + +if __name__ == '__main__': + unittest.main() + diff --git a/_imaging.c b/_imaging.c index 786363e24..09345c0dd 100644 --- a/_imaging.c +++ b/_imaging.c @@ -421,6 +421,7 @@ getlist(PyObject* arg, int* length, const char* wrong_length, int type) *length = n; PyErr_Clear(); + Py_DECREF(seq); return list; } @@ -1221,7 +1222,7 @@ _putdata(ImagingObject* self, PyObject* args) Py_ssize_t n, i, x, y; PyObject* data; - PyObject* seq; + PyObject* seq = NULL; PyObject* op; double scale = 1.0; double offset = 0.0; @@ -1329,6 +1330,7 @@ _putdata(ImagingObject* self, PyObject* args) op = PySequence_Fast_GET_ITEM(seq, i); if (!op || !getink(op, image, u.ink)) { + Py_DECREF(seq); return NULL; } /* FIXME: what about scale and offset? */ @@ -1342,6 +1344,8 @@ _putdata(ImagingObject* self, PyObject* args) } } + Py_XDECREF(seq); + Py_INCREF(Py_None); return Py_None; } From a649757f03c25213f54d58b3220372f83c43373b Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Thu, 16 Apr 2015 17:38:15 +0200 Subject: [PATCH 2/2] tests: add missing "from __future__ import division" --- Tests/check_webp_leaks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/check_webp_leaks.py b/Tests/check_webp_leaks.py index b5875c8ab..95162ad4a 100644 --- a/Tests/check_webp_leaks.py +++ b/Tests/check_webp_leaks.py @@ -1,3 +1,4 @@ +from __future__ import division from helper import unittest, PillowTestCase import sys from PIL import Image