summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorR David Murray <rdmurray@bitdance.com>2011-06-17 16:54:56 (GMT)
committerR David Murray <rdmurray@bitdance.com>2011-06-17 16:54:56 (GMT)
commit05ff9904010a488cc640637ac8255cae41b270dd (patch)
tree4dcec34c3a4b2c246bd0b299e96c0e93dae3b9c8
parent26de69dff824a9474ea0044afcbff2d30f109e1e (diff)
downloadcpython-05ff9904010a488cc640637ac8255cae41b270dd.zip
cpython-05ff9904010a488cc640637ac8255cae41b270dd.tar.gz
cpython-05ff9904010a488cc640637ac8255cae41b270dd.tar.bz2
#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.
-rw-r--r--Lib/mailbox.py4
-rw-r--r--Lib/test/test_mailbox.py33
-rw-r--r--Misc/NEWS2
3 files changed, 37 insertions, 2 deletions
diff --git a/Lib/mailbox.py b/Lib/mailbox.py
index 0e4f99b..b96b270 100644
--- a/Lib/mailbox.py
+++ b/Lib/mailbox.py
@@ -20,6 +20,7 @@ import email
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 @@ class Mailbox:
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
index 8dc7326..10317c3 100644
--- a/Lib/test/test_mailbox.py
+++ b/Lib/test/test_mailbox.py
@@ -1201,6 +1201,37 @@ class TestBabyl(TestMailbox):
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 @@ def test_main():
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
index 6cc0f03..ec8b72e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -25,6 +25,8 @@ Core and Builtins
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.