From b73b4a7b6315bd5649a2c61660bfb56089c96c3d Mon Sep 17 00:00:00 2001 From: wiredfool Date: Thu, 27 Mar 2014 22:17:27 -0700 Subject: [PATCH 1/4] Tests for #526 --- Tests/test_file_libtiff.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index a94257bc0..79abe5961 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -1,4 +1,5 @@ from tester import * +import warnings from PIL import Image, TiffImagePlugin @@ -34,6 +35,7 @@ def test_g4_tiff(): assert_equal(im.size, (500,500)) _assert_noerr(im) + im = None def test_g4_large(): file = "Tests/images/pport_g4.tif" @@ -295,3 +297,15 @@ def xtest_bw_compression_wRGB(): assert_exception(IOError, lambda: im.save(out, compression='group3')) assert_exception(IOError, lambda: im.save(out, compression='group4')) +def test_fp_leak(): + import os + + im = Image.open("Tests/images/lena_g4_500.tif") + fn = im.fp.fileno() + + assert_no_exception(lambda: os.fstat(fn)) + im.load() # this should close it. + assert_exception(OSError, lambda: os.fstat(fn)) + im = None # this should force even more closed. + assert_exception(OSError, lambda: os.fstat(fn)) + assert_exception(OSError, lambda: os.close(fn)) From 9552d9bc66d159f349863a9190e4ae882d870d6a Mon Sep 17 00:00:00 2001 From: wiredfool Date: Thu, 27 Mar 2014 22:18:40 -0700 Subject: [PATCH 2/4] close the fd, if possible. Fixes #526 --- PIL/TiffImagePlugin.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index 68a77e9ca..f3e30e82d 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -729,6 +729,9 @@ class TiffImageFile(ImageFile.ImageFile): self.tile = [] self.readonly = 0 + # libtiff closed the fp in a, we need to close self.fp, if possible + if hasattr(self.fp, 'close'): + self.fp.close() self.fp = None # might be shared if e < 0: From 937ae7790f3d9d184123e55a31bcaa7488a6cd23 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Thu, 27 Mar 2014 22:19:39 -0700 Subject: [PATCH 3/4] Renamed variables from reused single letter confusing names to something halfway descriptive --- PIL/TiffImagePlugin.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index f3e30e82d..18d5909dc 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -693,10 +693,11 @@ class TiffImageFile(ImageFile.ImageFile): if not len(self.tile) == 1: raise IOError("Not exactly one tile") - d, e, o, a = self.tile[0] - d = Image._getdecoder(self.mode, 'libtiff', a, self.decoderconfig) + # (self._compression, (extents tuple), 0, (rawmode, self._compression, fp)) + ignored, extents, ignored_2, args = self.tile[0] + decoder = Image._getdecoder(self.mode, 'libtiff', args, self.decoderconfig) try: - d.setimage(self.im, e) + decoder.setimage(self.im, extents) except ValueError: raise IOError("Couldn't set the image") @@ -712,19 +713,19 @@ class TiffImageFile(ImageFile.ImageFile): # with here by reordering. if Image.DEBUG: print ("have getvalue. just sending in a string from getvalue") - n,e = d.decode(self.fp.getvalue()) + n,err = decoder.decode(self.fp.getvalue()) elif hasattr(self.fp, "fileno"): # we've got a actual file on disk, pass in the fp. if Image.DEBUG: print ("have fileno, calling fileno version of the decoder.") self.fp.seek(0) - n,e = d.decode(b"fpfp") # 4 bytes, otherwise the trace might error out + n,err = decoder.decode(b"fpfp") # 4 bytes, otherwise the trace might error out else: # we have something else. if Image.DEBUG: print ("don't have fileno or getvalue. just reading") # UNDONE -- so much for that buffer size thing. - n, e = d.decode(self.fp.read()) + n,err = decoder.decode(self.fp.read()) self.tile = [] @@ -734,8 +735,8 @@ class TiffImageFile(ImageFile.ImageFile): self.fp.close() self.fp = None # might be shared - if e < 0: - raise IOError(e) + if err < 0: + raise IOError(err) self.load_end() From 65c17d41761c35cfe6d13c93aeda0d634cf82567 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Fri, 28 Mar 2014 08:35:18 -0700 Subject: [PATCH 4/4] Removed warning import, stray im=None, and moved os import to top --- Tests/test_file_libtiff.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 79abe5961..a53593a9e 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -1,5 +1,5 @@ from tester import * -import warnings +import os from PIL import Image, TiffImagePlugin @@ -35,7 +35,6 @@ def test_g4_tiff(): assert_equal(im.size, (500,500)) _assert_noerr(im) - im = None def test_g4_large(): file = "Tests/images/pport_g4.tif" @@ -298,8 +297,6 @@ def xtest_bw_compression_wRGB(): assert_exception(IOError, lambda: im.save(out, compression='group4')) def test_fp_leak(): - import os - im = Image.open("Tests/images/lena_g4_500.tif") fn = im.fp.fileno()