aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/asyncio/selector_events.py
diff options
context:
space:
mode:
authorAndrew Svetlov <andrew.svetlov@gmail.com>2019-05-16 16:30:16 +0300
committerMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2019-05-16 06:30:16 -0700
commit6e7890028213b30939327e7cf885bf097fc14472 (patch)
tree4a62f057bced495625105727114790a358dbdada /Lib/asyncio/selector_events.py
parentbfba8c373e362d48d4ee0e0cf55b8d9c169344ae (diff)
downloadcpython-6e7890028213b30939327e7cf885bf097fc14472.tar.gz
cpython-6e7890028213b30939327e7cf885bf097fc14472.zip
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
Diffstat (limited to 'Lib/asyncio/selector_events.py')
-rw-r--r--Lib/asyncio/selector_events.py17
1 files changed, 10 insertions, 7 deletions
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 29968214f8e..6461d307763 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.