]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-99941: Ensure that asyncio.Protocol.data_received receives immutable bytes (#100053)
authorDarioDaF <dario.fagotto@gmail.com>
Sat, 10 Dec 2022 23:07:02 +0000 (00:07 +0100)
committerGitHub <noreply@github.com>
Sat, 10 Dec 2022 23:07:02 +0000 (15:07 -0800)
Lib/asyncio/proactor_events.py
Lib/asyncio/streams.py
Lib/test/test_asyncio/test_proactor_events.py
Misc/NEWS.d/next/Windows/2022-12-06-11-16-46.gh-issue-99941.GmUQ6o.rst [new file with mode: 0644]

index c6aab408fc74107c29d99c3fca0272c143d68cf7..1e2a730cf368a99f51a049352a376eb4a63597b3 100644 (file)
@@ -288,7 +288,8 @@ class _ProactorReadPipeTransport(_ProactorBasePipeTransport,
                         # we got end-of-file so no need to reschedule a new read
                         return
 
-                    data = self._data[:length]
+                    # It's a new slice so make it immutable so protocols upstream don't have problems
+                    data = bytes(memoryview(self._data)[:length])
                 else:
                     # the future will be replaced by next proactor.recv call
                     fut.cancel()
index 3bd99043d0961c1fd1785f692444927b798402dd..0f9098b4195633c114dcd4496d9e92da339ba622 100644 (file)
@@ -688,7 +688,7 @@ class StreamReader:
             await self._wait_for_data('read')
 
         # This will work right even if buffer is less than n bytes
-        data = bytes(self._buffer[:n])
+        data = bytes(memoryview(self._buffer)[:n])
         del self._buffer[:n]
 
         self._maybe_resume_transport()
@@ -730,7 +730,7 @@ class StreamReader:
             data = bytes(self._buffer)
             self._buffer.clear()
         else:
-            data = bytes(self._buffer[:n])
+            data = bytes(memoryview(self._buffer)[:n])
             del self._buffer[:n]
         self._maybe_resume_transport()
         return data
index ae30185cef776a046a5d9c44877fdfebd9703c9d..6cb7dc300c533165087b9d14faebbd1d20538227 100644 (file)
@@ -75,7 +75,10 @@ class ProactorSocketTransportTests(test_utils.TestCase):
         called_buf = bytearray(self.buffer_size)
         called_buf[:len(buf)] = buf
         self.loop._proactor.recv_into.assert_called_with(self.sock, called_buf)
-        self.protocol.data_received.assert_called_with(bytearray(buf))
+        self.protocol.data_received.assert_called_with(buf)
+        # assert_called_with maps bytearray and bytes to the same thing so check manually
+        # regression test for https://github.com/python/cpython/issues/99941
+        self.assertIsInstance(self.protocol.data_received.call_args.args[0], bytes)
 
     @unittest.skipIf(sys.flags.optimize, "Assertions are disabled in optimized mode")
     def test_loop_reading_no_data(self):
diff --git a/Misc/NEWS.d/next/Windows/2022-12-06-11-16-46.gh-issue-99941.GmUQ6o.rst b/Misc/NEWS.d/next/Windows/2022-12-06-11-16-46.gh-issue-99941.GmUQ6o.rst
new file mode 100644 (file)
index 0000000..a019d72
--- /dev/null
@@ -0,0 +1,2 @@
+Ensure that :func:`asyncio.Protocol.data_received` receives an immutable
+:class:`bytes` object (as documented), instead of :class:`bytearray`.