mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-30 23:47:27 +03:00 
			
		
		
		
	Merge pull request #2974 from wiredfool/webp_leak
Fix memory leak when opening webp files
This commit is contained in:
		
						commit
						797d67b9a3
					
				|  | @ -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
									
								
							
							
						
						
									
										25
									
								
								Tests/test_webp_leaks.py
									
									
									
									
									
										Normal 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() | ||||||
|  | @ -410,6 +410,7 @@ PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args) | ||||||
|     uint8_t* buf; |     uint8_t* buf; | ||||||
|     int timestamp; |     int timestamp; | ||||||
|     PyObject* bytes; |     PyObject* bytes; | ||||||
|  |     PyObject* ret; | ||||||
|     WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self; |     WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self; | ||||||
| 
 | 
 | ||||||
|     if (!WebPAnimDecoderGetNext(decp->dec, &buf, ×tamp)) { |     if (!WebPAnimDecoderGetNext(decp->dec, &buf, ×tamp)) { | ||||||
|  | @ -419,7 +420,11 @@ PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args) | ||||||
| 
 | 
 | ||||||
|     bytes = PyBytes_FromStringAndSize((char *)buf, |     bytes = PyBytes_FromStringAndSize((char *)buf, | ||||||
|         decp->info.canvas_width * 4 * decp->info.canvas_height); |         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) | PyObject* _anim_decoder_has_more_frames(PyObject* self, PyObject* args) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user