Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Lib/test/test_io/test_memoryio.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,14 @@ def test_relative_seek(self):
memio.seek(1, 1)
self.assertEqual(memio.read(), buf[1:])

def test_issue141311(self):
memio = self.ioclass()
# Seek allows PY_SSIZE_T_MAX, read should handle that.
# Past end of buffer read should always return 0 (EOF).
self.assertEqual(sys.maxsize, memio.seek(sys.maxsize))
buf = bytearray(2)
self.assertEqual(0, memio.readinto(buf))

def test_unicode(self):
memio = self.ioclass()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix assertion failure in :class:`io.BytesIO` implementation of
:func:`~io.BufferedIOBase.readinto` when the current offset is at the max
offset and readinto is called.
5 changes: 3 additions & 2 deletions Modules/_io/bytesio.c
Original file line number Diff line number Diff line change
Expand Up @@ -609,8 +609,9 @@ _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer)
n = self->string_size - self->pos;
if (len > n) {
len = n;
if (len < 0)
len = 0;
if (len < 0) {
return PyLong_FromSsize_t(0);
}
}

assert(self->pos + len < PY_SSIZE_T_MAX);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it enough to fix this assertion?

Suggested change
assert(self->pos + len < PY_SSIZE_T_MAX);
assert(self->pos + len <= PY_SSIZE_T_MAX);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will but I worry about the later PyBytes_AS_STRING(self->buf) + self->pos as self->pos is PY_SSIZE_T_MAX and adding a large integer to a pointer then doing a memcpy from that computed address (even 0 bytes) feels like a path to undefined behavior to me. Happy to implement whichever you'd prefer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. If adding PY_SSIZE_T_MAX causes troubles, adding slightly smaller value will also cause troubles. Actually, if pos larger than the size of the array, ot is an undefined behaviour. So, a specoal case for empty read is needed too.

Expand Down
Loading