]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #27759: Fix selectors incorrectly retain invalid file descriptors.
authorYury Selivanov <yury@magic.io>
Thu, 15 Sep 2016 23:30:42 +0000 (19:30 -0400)
committerYury Selivanov <yury@magic.io>
Thu, 15 Sep 2016 23:30:42 +0000 (19:30 -0400)
Patch by Mark Williams.

Lib/selectors.py
Lib/test/test_selectors.py
Misc/NEWS

index d8769e35411523f0fd0b9fadd31dca0d7d77cbf2..89680a20a5be9e5b413813845f76e02f67859041 100644 (file)
@@ -408,7 +408,11 @@ if hasattr(select, 'epoll'):
                 epoll_events |= select.EPOLLIN
             if events & EVENT_WRITE:
                 epoll_events |= select.EPOLLOUT
-            self._epoll.register(key.fd, epoll_events)
+            try:
+                self._epoll.register(key.fd, epoll_events)
+            except BaseException:
+                super().unregister(fileobj)
+                raise
             return key
 
         def unregister(self, fileobj):
@@ -530,14 +534,18 @@ if hasattr(select, 'kqueue'):
 
         def register(self, fileobj, events, data=None):
             key = super().register(fileobj, events, data)
-            if events & EVENT_READ:
-                kev = select.kevent(key.fd, select.KQ_FILTER_READ,
-                                    select.KQ_EV_ADD)
-                self._kqueue.control([kev], 0, 0)
-            if events & EVENT_WRITE:
-                kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
-                                    select.KQ_EV_ADD)
-                self._kqueue.control([kev], 0, 0)
+            try:
+                if events & EVENT_READ:
+                    kev = select.kevent(key.fd, select.KQ_FILTER_READ,
+                                        select.KQ_EV_ADD)
+                    self._kqueue.control([kev], 0, 0)
+                if events & EVENT_WRITE:
+                    kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
+                                        select.KQ_EV_ADD)
+                    self._kqueue.control([kev], 0, 0)
+            except BaseException:
+                super().unregister(fileobj)
+                raise
             return key
 
         def unregister(self, fileobj):
index 454c17be99953c788e7d745ef73c94de47cc7f0a..852b2feb45fde3cba46f26b2516df5160e43d183 100644 (file)
@@ -9,6 +9,7 @@ from test import support
 from time import sleep
 import unittest
 import unittest.mock
+import tempfile
 from time import monotonic as time
 try:
     import resource
@@ -475,6 +476,16 @@ class EpollSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
 
     SELECTOR = getattr(selectors, 'EpollSelector', None)
 
+    def test_register_file(self):
+        # epoll(7) returns EPERM when given a file to watch
+        s = self.SELECTOR()
+        with tempfile.NamedTemporaryFile() as f:
+            with self.assertRaises(IOError):
+                s.register(f, selectors.EVENT_READ)
+            # the SelectorKey has been removed
+            with self.assertRaises(KeyError):
+                s.get_key(f)
+
 
 @unittest.skipUnless(hasattr(selectors, 'KqueueSelector'),
                      "Test needs selectors.KqueueSelector)")
@@ -482,6 +493,18 @@ class KqueueSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
 
     SELECTOR = getattr(selectors, 'KqueueSelector', None)
 
+    def test_register_bad_fd(self):
+        # a file descriptor that's been closed should raise an OSError
+        # with EBADF
+        s = self.SELECTOR()
+        bad_f = support.make_bad_fd()
+        with self.assertRaises(OSError) as cm:
+            s.register(bad_f, selectors.EVENT_READ)
+        self.assertEqual(cm.exception.errno, errno.EBADF)
+        # the SelectorKey has been removed
+        with self.assertRaises(KeyError):
+            s.get_key(bad_f)
+
 
 @unittest.skipUnless(hasattr(selectors, 'DevpollSelector'),
                      "Test needs selectors.DevpollSelector")
index 8f5ee3b8856a259c13e653320f791cbfdfc56263..9e61ef3d35bac821e3df0eff94aaeec5c5e54ebd 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -277,6 +277,9 @@ Library
 
 - Issue #28176: Fix callbacks race in asyncio.SelectorLoop.sock_connect.
 
+- Issue #27759: Fix selectors incorrectly retain invalid file descriptors.
+  Patch by Mark Williams.
+
 IDLE
 ----