summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYury Selivanov <yury@magic.io>2016-09-15 23:30:42 (GMT)
committerYury Selivanov <yury@magic.io>2016-09-15 23:30:42 (GMT)
commit525aedc5fae90e5195adb2d34ec33f1a773540fc (patch)
tree80298262b1fcc7e93cf76035e354535b89af2b8d
parentd6c6771fc9682713ff2ebae2cd02ddbd2b48f657 (diff)
downloadcpython-525aedc5fae90e5195adb2d34ec33f1a773540fc.zip
cpython-525aedc5fae90e5195adb2d34ec33f1a773540fc.tar.gz
cpython-525aedc5fae90e5195adb2d34ec33f1a773540fc.tar.bz2
Issue #27759: Fix selectors incorrectly retain invalid file descriptors.
Patch by Mark Williams.
-rw-r--r--Lib/selectors.py26
-rw-r--r--Lib/test/test_selectors.py23
-rw-r--r--Misc/NEWS3
3 files changed, 43 insertions, 9 deletions
diff --git a/Lib/selectors.py b/Lib/selectors.py
index d8769e3..89680a2 100644
--- a/Lib/selectors.py
+++ b/Lib/selectors.py
@@ -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):
diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py
index 454c17b..852b2fe 100644
--- a/Lib/test/test_selectors.py
+++ b/Lib/test/test_selectors.py
@@ -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")
diff --git a/Misc/NEWS b/Misc/NEWS
index 8f5ee3b..9e61ef3 100644
--- 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
----