bpo-33263: Fix FD leak in _SelectorSocketTransport (GH-6450)

* 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.
This commit is contained in:
Vlad Starostin 2018-05-21 11:13:45 +03:00 committed by Andrew Svetlov
parent 4054b172ab
commit a84d0b361a
3 changed files with 25 additions and 3 deletions

View file

@ -706,6 +706,12 @@ def _call_connection_lost(self, exc):
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 @@ def __init__(self, loop, sock, protocol, waiter=None,
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 @@ def resume_reading(self):
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 @@ def __init__(self, loop, sock, protocol, address=None,
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

View file

@ -871,6 +871,21 @@ def test_connection_lost(self):
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):

View file

@ -0,0 +1 @@
Fix FD leak in `_SelectorSocketTransport` Patch by Vlad Starostin.