Skip to content

Commit 3038d44

Browse files
committed
gh-157048: check for buffer errors before mutating in BytesIO.__init__
1 parent d9ad171 commit 3038d44

3 files changed

Lines changed: 19 additions & 4 deletions

File tree

Lib/test/test_io/test_memoryio.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,18 @@ def test_cow_mutable(self):
920920
memio = self.ioclass(ba)
921921
self.assertEqual(sys.getrefcount(ba), old_rc)
922922

923+
def test_write_with_export(self):
924+
memio = self.ioclass(b"abcd")
925+
memio.seek(2)
926+
with memio.getbuffer() as view:
927+
self.assertRaises(BufferError, memio.__init__, b"replacement")
928+
self.assertEqual(memio.tell(), 2)
929+
self.assertEqual(memio.getvalue(), b"abcd")
930+
self.assertEqual(bytes(view), b"abcd")
931+
memio.write(b"X")
932+
self.assertEqual(memio.getvalue(), b"abXd")
933+
934+
923935
class CStringIOTest(PyStringIOTest):
924936
ioclass = io.StringIO
925937
UnsupportedOperation = io.UnsupportedOperation
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Preserve the position and contents of :class:`io.BytesIO` when
2+
:meth:`!BytesIO.__init__` fails because a buffer is exported.

Modules/_io/bytesio.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,15 +1034,16 @@ static int
10341034
_io_BytesIO___init___impl(bytesio *self, PyObject *initvalue)
10351035
/*[clinic end generated code: output=65c0c51e24c5b621 input=3da5a74ee4c4f1ac]*/
10361036
{
1037-
/* In case, __init__ is called multiple times. */
1038-
self->string_size = 0;
1039-
self->pos = 0;
1040-
10411037
if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) {
10421038
PyErr_SetString(PyExc_BufferError,
10431039
"Existing exports of data: object cannot be re-sized");
10441040
return -1;
10451041
}
1042+
1043+
/* In case, __init__ is called multiple times. */
1044+
self->string_size = 0;
1045+
self->pos = 0;
1046+
10461047
if (initvalue && initvalue != Py_None) {
10471048
if (PyBytes_CheckExact(initvalue)) {
10481049
Py_XSETREF(self->buf, Py_NewRef(initvalue));

0 commit comments

Comments
 (0)