Skip to content

Commit f36fdb1

Browse files
[3.15] gh-160781: Fix BytesIO overflow handling for large sizes (GH-160783) (#160891)
(cherry picked from commit 7b727ab) Co-authored-by: Cody Maloney <cmaloney@users.noreply.github.com>
1 parent dcd2558 commit f36fdb1

4 files changed

Lines changed: 19 additions & 1 deletion

File tree

‎Lib/test/test_io/test_memoryio.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,10 @@ def test_issue141311(self):
565565
self.assertEqual(sys.maxsize, memio.seek(sys.maxsize))
566566
buf = bytearray(2)
567567
self.assertEqual(0, memio.readinto(buf))
568+
# Writing there must not overflow the buffer size.
569+
memio.seek(sys.maxsize - 1)
570+
self.assertRaises((MemoryError, OverflowError), memio.write, b"x")
571+
self.assertEqual(memio.getvalue(), b"")
568572

569573
def test_unicode(self):
570574
memio = self.ioclass()
@@ -881,6 +885,12 @@ def __index__(self):
881885
finally:
882886
size.result.release()
883887

888+
# Sizes above 2**31 - 1 must work where C long is 32-bit.
889+
if sys.maxsize > 2**31:
890+
stream = self.ioclass(b'abc')
891+
self.assertEqual(stream.truncate(2**31), 2**31)
892+
self.assertEqual(stream.getvalue(), b'abc')
893+
884894
def test_readinto_overlapping_buffer(self):
885895
with self.ioclass(b'abcd') as stream:
886896
with stream.getbuffer()[1:] as target:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :class:`io.BytesIO` raising :exc:`SystemError` instead of
2+
:exc:`OverflowError` when writing at a position close to
3+
:data:`sys.maxsize`.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :class:`io.BytesIO` implementation of :meth:`io.IOBase.truncate` rejecting
2+
sizes larger than ``2**31 - 1`` on Windows.

‎Modules/_io/bytesio.c‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ resize_buffer_lock_held(bytesio *self, size_t size)
210210
/* Major upsize; resize up to exact size */
211211
alloc = size + 1;
212212
}
213+
if (alloc > PY_SSIZE_T_MAX) {
214+
goto overflow;
215+
}
213216

214217
if (SHARED_BUF(self)) {
215218
if (unshare_buffer_lock_held(self, alloc) < 0)
@@ -701,7 +704,7 @@ _io_BytesIO_truncate_impl(bytesio *self, PyObject *size)
701704
new_size = self->pos;
702705
}
703706
else {
704-
new_size = PyLong_AsLong(size);
707+
new_size = PyNumber_AsSsize_t(size, PyExc_OverflowError);
705708
if (new_size == -1 && PyErr_Occurred()) {
706709
return NULL;
707710
}

0 commit comments

Comments
 (0)