Commit c057c385 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #23099: Closing io.BytesIO with exported buffer is rejected now to

prevent corrupting exported buffer.
parent b5e8e575
......@@ -563,7 +563,8 @@ than raw I/O does.
.. class:: BytesIO([initial_bytes])
A stream implementation using an in-memory bytes buffer. It inherits
:class:`BufferedIOBase`.
:class:`BufferedIOBase`. The buffer is discarded when the
:meth:`~IOBase.close` method is called.
The argument *initial_bytes* contains optional initial :class:`bytes` data.
......@@ -584,7 +585,7 @@ than raw I/O does.
.. note::
As long as the view exists, the :class:`BytesIO` object cannot be
resized.
resized or closed.
.. versionadded:: 3.2
......@@ -592,6 +593,7 @@ than raw I/O does.
Return :class:`bytes` containing the entire contents of the buffer.
.. method:: read1()
In :class:`BytesIO`, this is the same as :meth:`read`.
......@@ -858,7 +860,8 @@ Text I/O
.. class:: StringIO(initial_value='', newline='\\n')
An in-memory stream for text I/O.
An in-memory stream for text I/O. The text buffer is discarded when the
:meth:`~IOBase.close` method is called.
The initial value of the buffer (an empty string by default) can be set by
providing *initial_value*. The *newline* argument works like that of
......@@ -870,9 +873,7 @@ Text I/O
.. method:: getvalue()
Return a ``str`` containing the entire contents of the buffer at any
time before the :class:`StringIO` object's :meth:`close` method is
called.
Return a ``str`` containing the entire contents of the buffer.
Example usage::
......
......@@ -833,8 +833,14 @@ class BytesIO(BufferedIOBase):
def getbuffer(self):
"""Return a readable and writable view of the buffer.
"""
if self.closed:
raise ValueError("getbuffer on closed file")
return memoryview(self._buffer)
def close(self):
self._buffer.clear()
super().close()
def read(self, size=None):
if self.closed:
raise ValueError("read from closed file")
......
......@@ -398,14 +398,19 @@ class BytesIOMixin:
# raises a BufferError.
self.assertRaises(BufferError, memio.write, b'x' * 100)
self.assertRaises(BufferError, memio.truncate)
self.assertRaises(BufferError, memio.close)
self.assertFalse(memio.closed)
# Mutating the buffer updates the BytesIO
buf[3:6] = b"abc"
self.assertEqual(bytes(buf), b"123abc7890")
self.assertEqual(memio.getvalue(), b"123abc7890")
# After the buffer gets released, we can resize the BytesIO again
# After the buffer gets released, we can resize and close the BytesIO
# again
del buf
support.gc_collect()
memio.truncate()
memio.close()
self.assertRaises(ValueError, memio.getbuffer)
class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin,
......
......@@ -56,6 +56,9 @@ Core and Builtins
Library
-------
- Issue #23099: Closing io.BytesIO with exported buffer is rejected now to
prevent corrupting exported buffer.
- Issue #23363: Fix possible overflow in itertools.permutations.
- Issue #23364: Fix possible overflow in itertools.product.
......
......@@ -657,6 +657,7 @@ PyDoc_STRVAR(close_doc,
static PyObject *
bytesio_close(bytesio *self)
{
CHECK_EXPORTS(self);
if (self->buf != NULL) {
PyMem_Free(self->buf);
self->buf = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment