https://github.com/python/cpython/commit/2f4cca5467cfdf9d754a5d737b9e63ea0c1dc66f
commit: 2f4cca5467cfdf9d754a5d737b9e63ea0c1dc66f
branch: main
author: Timofei <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-07-25T13:14:49Z
summary:
gh-150621: avoid quadratic bytes slicing in
`asyncio.protocols._feed_data_to_buffered_proto` (#150622)
files:
M Lib/asyncio/protocols.py
M Lib/test/test_asyncio/test_protocols.py
diff --git a/Lib/asyncio/protocols.py b/Lib/asyncio/protocols.py
index 09987b164c66e5..c67a26c9e2986c 100644
--- a/Lib/asyncio/protocols.py
+++ b/Lib/asyncio/protocols.py
@@ -199,6 +199,7 @@ def process_exited(self):
def _feed_data_to_buffered_proto(proto, data):
data_len = len(data)
+ start = 0
while data_len:
buf = proto.get_buffer(data_len)
buf_len = len(buf)
@@ -206,11 +207,11 @@ def _feed_data_to_buffered_proto(proto, data):
raise RuntimeError('get_buffer() returned an empty buffer')
if buf_len >= data_len:
- buf[:data_len] = data
+ buf[:data_len] = data[start:] if start else data
proto.buffer_updated(data_len)
return
else:
- buf[:buf_len] = data[:buf_len]
+ buf[:buf_len] = data[start:start + buf_len]
proto.buffer_updated(buf_len)
- data = data[buf_len:]
- data_len = len(data)
+ start += buf_len
+ data_len -= buf_len
diff --git a/Lib/test/test_asyncio/test_protocols.py
b/Lib/test/test_asyncio/test_protocols.py
index 643199962b8af0..38f1e3fba90cfd 100644
--- a/Lib/test/test_asyncio/test_protocols.py
+++ b/Lib/test/test_asyncio/test_protocols.py
@@ -2,6 +2,7 @@
from unittest import mock
import asyncio
+from asyncio import protocols
def tearDownModule():
@@ -63,5 +64,32 @@ def test_subprocess_protocol(self):
self.assertNotHasAttr(sp, '__dict__')
-if __name__ == '__main__':
+class FeedDataToBufferedProtoTests(unittest.TestCase):
+ def _make_proto(self, bufsize):
+ received = bytearray()
+ buf = bytearray(bufsize)
+
+ class P(asyncio.BufferedProtocol):
+ def get_buffer(self, sizehint):
+ return buf
+
+ def buffer_updated(self, nbytes):
+ received.extend(buf[:nbytes])
+
+ return P(), received
+
+ def test_large_multi_iteration(self):
+ proto, received = self._make_proto(64)
+ data = bytes(range(256)) * 16
+ protocols._feed_data_to_buffered_proto(proto, data)
+ self.assertEqual(bytes(received), data)
+
+ def test_memoryview_input(self):
+ proto, received = self._make_proto(64)
+ payload = b"y" * 200
+ protocols._feed_data_to_buffered_proto(proto, memoryview(payload))
+ self.assertEqual(bytes(received), payload)
+
+
+if __name__ == "__main__":
unittest.main()
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]