From: Nir Soffer Date: Wed, 26 Jul 2017 23:24:52 +0000 (+0300) Subject: bpo-30980: Fix double close in asyncore.file_wrapper (#2789) (#2900) X-Git-Tag: v2.7.14rc1~33 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=29094cec7cddd561cac16ce93443ca72d740de4d;p=python bpo-30980: Fix double close in asyncore.file_wrapper (#2789) (#2900) * bpo-30980: Fix close test to fail test_close_twice was not considering the fact that file_wrapper is duping the file descriptor. Closing the original descriptor left the duped one open, hiding the fact that close protection is not effective. * bpo-30980: Fix double close protection Invalidated self.fd before closing, handling correctly the case when os.close raises. * bpo-30980: Fix fd leak introduced in the fixed test --- diff --git a/Lib/asyncore.py b/Lib/asyncore.py index 29099bdf5c..105982f790 100644 --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -633,7 +633,11 @@ if os.name == 'posix': write = send def close(self): - os.close(self.fd) + if self.fd < 0: + return + fd = self.fd + self.fd = -1 + os.close(fd) def fileno(self): return self.fd diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py index dc2b626f1e..693d67cd8a 100644 --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -442,6 +442,19 @@ class FileWrapperTest(unittest.TestCase): asyncore.loop(timeout=0.01, use_poll=True, count=2) self.assertEqual(b"".join(data), self.d) + def test_close_twice(self): + fd = os.open(TESTFN, os.O_RDONLY) + f = asyncore.file_wrapper(fd) + os.close(fd) + + os.close(f.fd) # file_wrapper dupped fd + with self.assertRaises(OSError): + f.close() + + self.assertEqual(f.fd, -1) + # calling close twice should not fail + f.close() + class BaseTestHandler(asyncore.dispatcher):