https://github.com/python/cpython/commit/8bfda5553c0f8ac1163b4ce4ca7b8b632a853f51
commit: 8bfda5553c0f8ac1163b4ce4ca7b8b632a853f51
branch: main
author: Jelle Zijlstra <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-10-22T15:26:56-07:00
summary:
gh-159739: Recheck BytesIO state after converting truncate size (#160190)
A size object's __index__() can close a BytesIO or export its buffer after
truncate() checks the stream. Continuing can dereference a cleared buffer or
resize storage behind a live view. Recheck the stream state after size
conversion. Backport to 3.15 and 3.14; on 3.14, put the regression test in
Lib/test/test_memoryio.py.
files:
A Misc/NEWS.d/next/Library/2026-10-21-21-26-10.gh-issue-159739.rVWF2a.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 90bdc791787439..999bd5bc007b2e 100644
--- a/Lib/test/test_io/test_memoryio.py
+++ b/Lib/test/test_io/test_memoryio.py
@@ -962,6 +962,28 @@ class CBytesIOTest(PyBytesIOTest):
ioclass = io.BytesIO
UnsupportedOperation = io.UnsupportedOperation
+ def test_truncate_size_changes_stream(self):
+ class Size:
+ def __init__(self, action):
+ self.action = action
+
+ def __index__(self):
+ self.result = self.action()
+ return 0
+
+ stream = self.ioclass(b'abc')
+ with self.assertRaises(ValueError):
+ stream.truncate(Size(stream.close))
+
+ with self.ioclass(b'abc') as stream:
+ size = Size(stream.getbuffer)
+ try:
+ with self.assertRaises(BufferError):
+ stream.truncate(size)
+ self.assertEqual(stream.getvalue(), b'abc')
+ finally:
+ size.result.release()
+
def test_readinto_overlapping_buffer(self):
with self.ioclass(b'abcd') as stream:
with stream.getbuffer()[1:] as target:
diff --git
a/Misc/NEWS.d/next/Library/2026-10-21-21-26-10.gh-issue-159739.rVWF2a.rst
b/Misc/NEWS.d/next/Library/2026-10-21-21-26-10.gh-issue-159739.rVWF2a.rst
new file mode 100644
index 00000000000000..f2e13ee926eaa1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-21-21-26-10.gh-issue-159739.rVWF2a.rst
@@ -0,0 +1 @@
+Fix the ``truncate`` method on :class:`io.BytesIO` when converting its size
argument closes the stream or exports its buffer.
diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c
index 2374a43ef74eab..aa74d9b0c721a4 100644
--- a/Modules/_io/bytesio.c
+++ b/Modules/_io/bytesio.c
@@ -754,6 +754,8 @@ _io_BytesIO_truncate_impl(bytesio *self, PyObject *size)
"negative size value %zd", new_size);
return NULL;
}
+ CHECK_CLOSED(self);
+ CHECK_EXPORTS(self);
}
if (new_size < self->string_size) {
_______________________________________________
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]