From 6e7890028213b30939327e7cf885bf097fc14472 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 16 May 2019 16:30:16 +0300 Subject: [PATCH] bpo-35589: Prevent buffer copy in sock_sendall() (GH-11418) No NEWs is needed since the problem was introduced on master only and never released. https://bugs.python.org/issue35589 --- Lib/asyncio/selector_events.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index 29968214f8..6461d30776 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -428,32 +428,35 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop): if n == len(data): # all data sent return - else: - data = bytearray(memoryview(data)[n:]) fut = self.create_future() fd = sock.fileno() fut.add_done_callback( functools.partial(self._sock_write_done, fd)) - self.add_writer(fd, self._sock_sendall, fut, sock, data) + # use a trick with a list in closure to store a mutable state + self.add_writer(fd, self._sock_sendall, fut, sock, + memoryview(data), [n]) return await fut - def _sock_sendall(self, fut, sock, data): + def _sock_sendall(self, fut, sock, view, pos): if fut.done(): # Future cancellation can be scheduled on previous loop iteration return + start = pos[0] try: - n = sock.send(data) + n = sock.send(view[start:]) except (BlockingIOError, InterruptedError): return except Exception as exc: fut.set_exception(exc) return - if n == len(data): + start += n + + if start == len(view): fut.set_result(None) else: - del data[:n] + pos[0] = start async def sock_connect(self, sock, address): """Connect to a remote socket at address. -- 2.40.0