From 6e7890028213b30939327e7cf885bf097fc14472 Mon Sep 17 00:00:00 2001
From: Andrew Svetlov <andrew.svetlov@gmail.com>
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.49.0