Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3845521

Browse files
committed
asyncio: Fix deadlock in readexactly(). Fixes issue #20154.
1 parent a101bdb commit 3845521

2 files changed

Lines changed: 21 additions & 10 deletions

File tree

Lib/asyncio/streams.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ def __init__(self, limit=_DEFAULT_LIMIT, loop=None):
220220
if loop is None:
221221
loop = events.get_event_loop()
222222
self._loop = loop
223+
# TODO: Use a bytearray for a buffer, like the transport.
223224
self._buffer = collections.deque() # Deque of bytes objects.
224225
self._byte_count = 0 # Bytes in buffer.
225226
self._eof = False # Whether we're done.
@@ -384,15 +385,23 @@ def readexactly(self, n):
384385
if self._exception is not None:
385386
raise self._exception
386387

387-
if n <= 0:
388-
return b''
388+
# There used to be "optimized" code here. It created its own
389+
# Future and waited until self._buffer had at least the n
390+
# bytes, then called read(n). Unfortunately, this could pause
391+
# the transport if the argument was larger than the pause
392+
# limit (which is twice self._limit). So now we just read()
393+
# into a local buffer.
394+
395+
blocks = []
396+
while n > 0:
397+
block = yield from self.read(n)
398+
if not block:
399+
break
400+
blocks.append(block)
401+
n -= len(block)
389402

390-
while self._byte_count < n and not self._eof:
391-
assert not self._waiter
392-
self._waiter = futures.Future(loop=self._loop)
393-
try:
394-
yield from self._waiter
395-
finally:
396-
self._waiter = None
403+
# TODO: Raise EOFError if we break before n == 0? (That would
404+
# be a change in specification, but I've always had to add an
405+
# explicit size check to the caller.)
397406

398-
return (yield from self.read(n))
407+
return b''.join(blocks)

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ Core and Builtins
7575
Library
7676
-------
7777

78+
- Issue #20154: Deadlock in asyncio.StreamReader.readexactly().
79+
7880
- Issue #16113: Remove sha3 module again.
7981

8082
- Issue #20111: pathlib.Path.with_suffix() now sanity checks the given suffix.

0 commit comments

Comments
 (0)