diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py index 464fbf67a84b83d..8780796ce831ee1 100644 --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -923,6 +923,18 @@ def test_cow_mutable(self): memio = self.ioclass(ba) self.assertEqual(sys.getrefcount(ba), old_rc) + def test_write_with_export(self): + memio = self.ioclass(b"abcd") + memio.seek(2) + with memio.getbuffer() as view: + self.assertRaises(BufferError, memio.__init__, b"replacement") + self.assertEqual(memio.tell(), 2) + self.assertEqual(memio.getvalue(), b"abcd") + self.assertEqual(bytes(view), b"abcd") + memio.write(b"X") + self.assertEqual(memio.getvalue(), b"abXd") + + class CStringIOTest(PyStringIOTest): ioclass = io.StringIO UnsupportedOperation = io.UnsupportedOperation diff --git a/Misc/NEWS.d/next/Library/2026-09-06-15-23-24.gh-issue-157048.UtFyiJ.rst b/Misc/NEWS.d/next/Library/2026-09-06-15-23-24.gh-issue-157048.UtFyiJ.rst new file mode 100644 index 000000000000000..1638968e475ca4a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-06-15-23-24.gh-issue-157048.UtFyiJ.rst @@ -0,0 +1,2 @@ +Preserve the position and contents of :class:`io.BytesIO` when +:meth:`!BytesIO.__init__` fails because a buffer is exported. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 73241471f69d6c9..6ed88357220c944 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -1078,15 +1078,16 @@ static int _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue) /*[clinic end generated code: output=65c0c51e24c5b621 input=3da5a74ee4c4f1ac]*/ { - /* In case, __init__ is called multiple times. */ - self->string_size = 0; - self->pos = 0; - if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) { PyErr_SetString(PyExc_BufferError, "Existing exports of data: object cannot be re-sized"); return -1; } + + /* In case, __init__ is called multiple times. */ + self->string_size = 0; + self->pos = 0; + if (initvalue && initvalue != Py_None) { if (PyBytes_CheckExact(initvalue)) { Py_XSETREF(self->buf, Py_NewRef(initvalue));