[Python-checkins] cpython (3.2): #11767: use context manager to close file in __getitem__ to prevent FD leak

r.david.murray python-checkins at python.org
Fri Jun 17 19:10:30 CEST 2011


http://hg.python.org/cpython/rev/fea1920ae75f
changeset:   70843:fea1920ae75f
branch:      3.2
parent:      70840:f6d6afe53385
user:        R David Murray <rdmurray at bitdance.com>
date:        Fri Jun 17 12:54:56 2011 -0400
summary:
  #11767: use context manager to close file in __getitem__ to prevent FD leak

All of the other methods in mailbox that create message objects take care to
close the file descriptors they use, so it seems to make sense to have
__getitem__ do so as well.

Patch by Filip Gruszczyński.

files:
  Lib/mailbox.py           |   4 ++-
  Lib/test/test_mailbox.py |  33 +++++++++++++++++++++++++++-
  Misc/NEWS                |   2 +
  3 files changed, 37 insertions(+), 2 deletions(-)


diff --git a/Lib/mailbox.py b/Lib/mailbox.py
--- a/Lib/mailbox.py
+++ b/Lib/mailbox.py
@@ -20,6 +20,7 @@
 import email.message
 import email.generator
 import io
+import contextlib
 try:
     if sys.platform == 'os2emx':
         # OS/2 EMX fcntl() not adequate
@@ -76,7 +77,8 @@
         if not self._factory:
             return self.get_message(key)
         else:
-            return self._factory(self.get_file(key))
+            with contextlib.closing(self.get_file(key)) as file:
+                return self._factory(file)
 
     def get_message(self, key):
         """Return a Message representation or raise a KeyError."""
diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py
--- a/Lib/test/test_mailbox.py
+++ b/Lib/test/test_mailbox.py
@@ -1201,6 +1201,37 @@
         self.assertEqual(set(self._box.get_labels()), set(['blah']))
 
 
+class FakeFileLikeObject:
+
+    def __init__(self):
+        self.closed = False
+
+    def close(self):
+        self.closed = True
+
+
+class FakeMailBox(mailbox.Mailbox):
+
+    def __init__(self):
+        mailbox.Mailbox.__init__(self, '', lambda file: None)
+        self.files = [FakeFileLikeObject() for i in range(10)]
+
+    def get_file(self, key):
+        return self.files[key]
+
+
+class TestFakeMailBox(unittest.TestCase):
+
+    def test_closing_fd(self):
+        box = FakeMailBox()
+        for i in range(10):
+            self.assertFalse(box.files[i].closed)
+        for i in range(10):
+            box[i]
+        for i in range(10):
+            self.assertTrue(box.files[i].closed)
+
+
 class TestMessage(TestBase):
 
     _factory = mailbox.Message      # Overridden by subclasses to reuse tests
@@ -2113,7 +2144,7 @@
              TestBabyl, TestMessage, TestMaildirMessage, TestMboxMessage,
              TestMHMessage, TestBabylMessage, TestMMDFMessage,
              TestMessageConversion, TestProxyFile, TestPartialFile,
-             MaildirTestCase)
+             MaildirTestCase, TestFakeMailBox)
     support.run_unittest(*tests)
     support.reap_children()
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -25,6 +25,8 @@
 Library
 -------
 
+- Issue #11767: Correct file descriptor leak in mailbox's __getitem__ method.
+
 - Issue #12133: AbstractHTTPHandler.do_open() of urllib.request closes the HTTP
   connection if its getresponse() method fails with a socket error. Patch
   written by Ezio Melotti.

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list