From: Andrew Svetlov Date: Thu, 16 May 2019 13:30:16 +0000 (+0300) Subject: bpo-35589: Prevent buffer copy in sock_sendall() (GH-11418) X-Git-Tag: v3.8.0b1~348 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6e7890028213b30939327e7cf885bf097fc14472;p=thirdparty%2FPython%2Fcpython.git 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 --- diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index 29968214f8ed..6461d3077633 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.