https://github.com/python/cpython/commit/f0986f385ecac3e82bd387e3e6dc420e1d4e653f
commit: f0986f385ecac3e82bd387e3e6dc420e1d4e653f
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-10-20T11:13:39-07:00
summary:

[3.15] gh-159739: Handle overlapping buffers in BytesIO.readinto (GH-159777) 
(#159902)



(cherry picked from commit 17df836e6d4ba3ce0a28cfe98efedf7c7b4f0e49)

Co-authored-by: Jelle Zijlstra <[email protected]>
Co-authored-by: Jelle Zijlstra <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-10-19-20-38-17.gh-issue-159739.a81270.rst
M Lib/test/test_io/test_memoryio.py
M Modules/_io/bytesio.c

diff --git a/Lib/test/test_io/test_memoryio.py 
b/Lib/test/test_io/test_memoryio.py
index 7f2eddd7ae7839e..2ee3a1d1562c8b4 100644
--- a/Lib/test/test_io/test_memoryio.py
+++ b/Lib/test/test_io/test_memoryio.py
@@ -859,6 +859,12 @@ class CBytesIOTest(PyBytesIOTest):
     ioclass = io.BytesIO
     UnsupportedOperation = io.UnsupportedOperation
 
+    def test_readinto_overlapping_buffer(self):
+        with self.ioclass(b'abcd') as stream:
+            with stream.getbuffer()[1:] as target:
+                self.assertEqual(stream.readinto(target), 3)
+            self.assertEqual(stream.getvalue(), b'aabc')
+
     def test_getstate(self):
         memio = self.ioclass()
         state = memio.__getstate__()
diff --git 
a/Misc/NEWS.d/next/Library/2026-10-19-20-38-17.gh-issue-159739.a81270.rst 
b/Misc/NEWS.d/next/Library/2026-10-19-20-38-17.gh-issue-159739.a81270.rst
new file mode 100644
index 000000000000000..413fc0d7f18f680
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-19-20-38-17.gh-issue-159739.a81270.rst
@@ -0,0 +1 @@
+Fix :class:`io.BytesIO` reads into overlapping views of the same buffer.
diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c
index 9ea197d29f30960..17ae3a82acad2fe 100644
--- a/Modules/_io/bytesio.c
+++ b/Modules/_io/bytesio.c
@@ -670,7 +670,7 @@ _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer)
 
     assert(self->pos + len <= PY_SSIZE_T_MAX);
     assert(len >= 0);
-    memcpy(buffer->buf, PyBytes_AS_STRING(self->buf) + self->pos, len);
+    memmove(buffer->buf, PyBytes_AS_STRING(self->buf) + self->pos, len);
     self->pos += len;
 
     return PyLong_FromSsize_t(len);

_______________________________________________
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]

Reply via email to