]> granicus.if.org Git - python/commitdiff
bpo-33263: Fix FD leak in _SelectorSocketTransport (GH-6450)
authorVlad Starostin <drtyrsa@yandex.ru>
Mon, 21 May 2018 08:13:45 +0000 (11:13 +0300)
committerAndrew Svetlov <andrew.svetlov@gmail.com>
Mon, 21 May 2018 08:13:45 +0000 (11:13 +0300)
* bpo-33263 Fix FD leak in _SelectorSocketTransport. (GH-6450)

Under particular circumstances _SelectorSocketTransport can try to add a reader
even the transport is already being closed. This can lead to FD leak and
invalid stated of the following connections. Fixed the SelectorSocketTransport
to add the reader only if the trasport is still active.

Lib/asyncio/selector_events.py
Lib/test/test_asyncio/test_selector_events.py
Misc/NEWS.d/next/Library/2018-04-11-20-29-19.bpo-33263.B56Hc1.rst [new file with mode: 0644]

index 354bf9d1c2def15774deedfa62db1900eb30afda..f9533a1d77be54cf779ac25a25bf02c82e4732ea 100644 (file)
@@ -706,6 +706,12 @@ class _SelectorTransport(transports._FlowControlMixin,
     def get_write_buffer_size(self):
         return len(self._buffer)
 
+    def _add_reader(self, fd, callback, *args):
+        if self._closing:
+            return
+
+        self._loop._add_reader(fd, callback, *args)
+
 
 class _SelectorSocketTransport(_SelectorTransport):
 
@@ -732,7 +738,7 @@ class _SelectorSocketTransport(_SelectorTransport):
 
         self._loop.call_soon(self._protocol.connection_made, self)
         # only start reading when connection_made() has been called
-        self._loop.call_soon(self._loop._add_reader,
+        self._loop.call_soon(self._add_reader,
                              self._sock_fd, self._read_ready)
         if waiter is not None:
             # only wake up the waiter when connection_made() has been called
@@ -754,7 +760,7 @@ class _SelectorSocketTransport(_SelectorTransport):
         if self._closing or not self._paused:
             return
         self._paused = False
-        self._loop._add_reader(self._sock_fd, self._read_ready)
+        self._add_reader(self._sock_fd, self._read_ready)
         if self._loop.get_debug():
             logger.debug("%r resumes reading", self)
 
@@ -930,7 +936,7 @@ class _SelectorDatagramTransport(_SelectorTransport):
         self._address = address
         self._loop.call_soon(self._protocol.connection_made, self)
         # only start reading when connection_made() has been called
-        self._loop.call_soon(self._loop._add_reader,
+        self._loop.call_soon(self._add_reader,
                              self._sock_fd, self._read_ready)
         if waiter is not None:
             # only wake up the waiter when connection_made() has been called
index 219ab0eb5b8b6611e45fae0d26474004bad19204..684c29dec3e283a70bfb362beea623d2740a184d 100644 (file)
@@ -871,6 +871,21 @@ class SelectorTransportTests(test_utils.TestCase):
         self.assertIsNone(tr._protocol)
         self.assertIsNone(tr._loop)
 
+    def test__add_reader(self):
+        tr = self.create_transport()
+        tr._buffer.extend(b'1')
+        tr._add_reader(7, mock.sentinel)
+        self.assertTrue(self.loop.readers)
+
+        tr._force_close(None)
+
+        self.assertTrue(tr.is_closing())
+        self.assertFalse(self.loop.readers)
+
+        # can not add readers after closing
+        tr._add_reader(7, mock.sentinel)
+        self.assertFalse(self.loop.readers)
+
 
 class SelectorSocketTransportTests(test_utils.TestCase):
 
diff --git a/Misc/NEWS.d/next/Library/2018-04-11-20-29-19.bpo-33263.B56Hc1.rst b/Misc/NEWS.d/next/Library/2018-04-11-20-29-19.bpo-33263.B56Hc1.rst
new file mode 100644 (file)
index 0000000..77994f6
--- /dev/null
@@ -0,0 +1 @@
+Fix FD leak in `_SelectorSocketTransport`  Patch by Vlad Starostin.