Skip to content

Commit 1bb68ba

Browse files
authored
gh-99941: Ensure that asyncio.Protocol.data_received receives immutable bytes (#100053)
1 parent d5f8a2b commit 1bb68ba

File tree

4 files changed

+10
-4
lines changed

4 files changed

+10
-4
lines changed

Lib/asyncio/proactor_events.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,8 @@ def _loop_reading(self, fut=None):
288288
# we got end-of-file so no need to reschedule a new read
289289
return
290290

291-
data = self._data[:length]
291+
# It's a new slice so make it immutable so protocols upstream don't have problems
292+
data = bytes(memoryview(self._data)[:length])
292293
else:
293294
# the future will be replaced by next proactor.recv call
294295
fut.cancel()

Lib/asyncio/streams.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ async def read(self, n=-1):
688688
await self._wait_for_data('read')
689689

690690
# This will work right even if buffer is less than n bytes
691-
data = bytes(self._buffer[:n])
691+
data = bytes(memoryview(self._buffer)[:n])
692692
del self._buffer[:n]
693693

694694
self._maybe_resume_transport()
@@ -730,7 +730,7 @@ async def readexactly(self, n):
730730
data = bytes(self._buffer)
731731
self._buffer.clear()
732732
else:
733-
data = bytes(self._buffer[:n])
733+
data = bytes(memoryview(self._buffer)[:n])
734734
del self._buffer[:n]
735735
self._maybe_resume_transport()
736736
return data

Lib/test/test_asyncio/test_proactor_events.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ def test_loop_reading_data(self):
7575
called_buf = bytearray(self.buffer_size)
7676
called_buf[:len(buf)] = buf
7777
self.loop._proactor.recv_into.assert_called_with(self.sock, called_buf)
78-
self.protocol.data_received.assert_called_with(bytearray(buf))
78+
self.protocol.data_received.assert_called_with(buf)
79+
# assert_called_with maps bytearray and bytes to the same thing so check manually
80+
# regression test for https://github.com/python/cpython/issues/99941
81+
self.assertIsInstance(self.protocol.data_received.call_args.args[0], bytes)
7982

8083
@unittest.skipIf(sys.flags.optimize, "Assertions are disabled in optimized mode")
8184
def test_loop_reading_no_data(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Ensure that :func:`asyncio.Protocol.data_received` receives an immutable
2+
:class:`bytes` object (as documented), instead of :class:`bytearray`.

0 commit comments

Comments
 (0)