Skip to content

Commit b8b8000

Browse files
miss-islingtondrtyrsa
authored andcommitted
bpo-33263: Fix FD leak in _SelectorSocketTransport (GH-6450) (#7022)
* 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. (cherry picked from commit a84d0b3) Co-authored-by: Vlad Starostin <[email protected]>
1 parent 4ecdc11 commit b8b8000

File tree

3 files changed

+25
-3
lines changed

3 files changed

+25
-3
lines changed

‎Lib/asyncio/selector_events.py‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,12 @@ def _call_connection_lost(self, exc):
706706
def get_write_buffer_size(self):
707707
return len(self._buffer)
708708

709+
def _add_reader(self, fd, callback, *args):
710+
if self._closing:
711+
return
712+
713+
self._loop._add_reader(fd, callback, *args)
714+
709715

710716
class _SelectorSocketTransport(_SelectorTransport):
711717

@@ -732,7 +738,7 @@ def __init__(self, loop, sock, protocol, waiter=None,
732738

733739
self._loop.call_soon(self._protocol.connection_made, self)
734740
# only start reading when connection_made() has been called
735-
self._loop.call_soon(self._loop._add_reader,
741+
self._loop.call_soon(self._add_reader,
736742
self._sock_fd, self._read_ready)
737743
if waiter is not None:
738744
# only wake up the waiter when connection_made() has been called
@@ -754,7 +760,7 @@ def resume_reading(self):
754760
if self._closing or not self._paused:
755761
return
756762
self._paused = False
757-
self._loop._add_reader(self._sock_fd, self._read_ready)
763+
self._add_reader(self._sock_fd, self._read_ready)
758764
if self._loop.get_debug():
759765
logger.debug("%r resumes reading", self)
760766

@@ -930,7 +936,7 @@ def __init__(self, loop, sock, protocol, address=None,
930936
self._address = address
931937
self._loop.call_soon(self._protocol.connection_made, self)
932938
# only start reading when connection_made() has been called
933-
self._loop.call_soon(self._loop._add_reader,
939+
self._loop.call_soon(self._add_reader,
934940
self._sock_fd, self._read_ready)
935941
if waiter is not None:
936942
# only wake up the waiter when connection_made() has been called

‎Lib/test/test_asyncio/test_selector_events.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,21 @@ def test_connection_lost(self):
871871
self.assertIsNone(tr._protocol)
872872
self.assertIsNone(tr._loop)
873873

874+
def test__add_reader(self):
875+
tr = self.create_transport()
876+
tr._buffer.extend(b'1')
877+
tr._add_reader(7, mock.sentinel)
878+
self.assertTrue(self.loop.readers)
879+
880+
tr._force_close(None)
881+
882+
self.assertTrue(tr.is_closing())
883+
self.assertFalse(self.loop.readers)
884+
885+
# can not add readers after closing
886+
tr._add_reader(7, mock.sentinel)
887+
self.assertFalse(self.loop.readers)
888+
874889

875890
class SelectorSocketTransportTests(test_utils.TestCase):
876891

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix FD leak in `_SelectorSocketTransport` Patch by Vlad Starostin.

0 commit comments

Comments
 (0)