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. ...@@ -563,7 +563,8 @@ than raw I/O does.
.. class:: BytesIO([initial_bytes]) .. class:: BytesIO([initial_bytes])
A stream implementation using an in-memory bytes buffer. It inherits 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. The argument *initial_bytes* contains optional initial :class:`bytes` data.
...@@ -584,7 +585,7 @@ than raw I/O does. ...@@ -584,7 +585,7 @@ than raw I/O does.
.. note:: .. note::
As long as the view exists, the :class:`BytesIO` object cannot be As long as the view exists, the :class:`BytesIO` object cannot be
resized. resized or closed.
.. versionadded:: 3.2 .. versionadded:: 3.2
...@@ -592,6 +593,7 @@ than raw I/O does. ...@@ -592,6 +593,7 @@ than raw I/O does.
Return :class:`bytes` containing the entire contents of the buffer. Return :class:`bytes` containing the entire contents of the buffer.
.. method:: read1() .. method:: read1()
In :class:`BytesIO`, this is the same as :meth:`read`. In :class:`BytesIO`, this is the same as :meth:`read`.
...@@ -858,7 +860,8 @@ Text I/O ...@@ -858,7 +860,8 @@ Text I/O
.. class:: StringIO(initial_value='', newline='\\n') .. 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 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 providing *initial_value*. The *newline* argument works like that of
...@@ -870,9 +873,7 @@ Text I/O ...@@ -870,9 +873,7 @@ Text I/O
.. method:: getvalue() .. method:: getvalue()
Return a ``str`` containing the entire contents of the buffer at any Return a ``str`` containing the entire contents of the buffer.
time before the :class:`StringIO` object's :meth:`close` method is
called.
Example usage:: Example usage::
......
...@@ -833,8 +833,14 @@ class BytesIO(BufferedIOBase): ...@@ -833,8 +833,14 @@ class BytesIO(BufferedIOBase):
def getbuffer(self): def getbuffer(self):
"""Return a readable and writable view of the buffer. """Return a readable and writable view of the buffer.
""" """
if self.closed:
raise ValueError("getbuffer on closed file")
return memoryview(self._buffer) return memoryview(self._buffer)
def close(self):
self._buffer.clear()
super().close()
def read(self, size=None): def read(self, size=None):
if self.closed: if self.closed:
raise ValueError("read from closed file") raise ValueError("read from closed file")
......
...@@ -398,14 +398,19 @@ class BytesIOMixin: ...@@ -398,14 +398,19 @@ class BytesIOMixin:
# raises a BufferError. # raises a BufferError.
self.assertRaises(BufferError, memio.write, b'x' * 100) self.assertRaises(BufferError, memio.write, b'x' * 100)
self.assertRaises(BufferError, memio.truncate) self.assertRaises(BufferError, memio.truncate)
self.assertRaises(BufferError, memio.close)
self.assertFalse(memio.closed)
# Mutating the buffer updates the BytesIO # Mutating the buffer updates the BytesIO
buf[3:6] = b"abc" buf[3:6] = b"abc"
self.assertEqual(bytes(buf), b"123abc7890") self.assertEqual(bytes(buf), b"123abc7890")
self.assertEqual(memio.getvalue(), 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 del buf
support.gc_collect() support.gc_collect()
memio.truncate() memio.truncate()
memio.close()
self.assertRaises(ValueError, memio.getbuffer)
class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin,
......
...@@ -56,6 +56,9 @@ Core and Builtins ...@@ -56,6 +56,9 @@ Core and Builtins
Library 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 #23363: Fix possible overflow in itertools.permutations.
- Issue #23364: Fix possible overflow in itertools.product. - Issue #23364: Fix possible overflow in itertools.product.
......
...@@ -657,6 +657,7 @@ PyDoc_STRVAR(close_doc, ...@@ -657,6 +657,7 @@ PyDoc_STRVAR(close_doc,
static PyObject * static PyObject *
bytesio_close(bytesio *self) bytesio_close(bytesio *self)
{ {
CHECK_EXPORTS(self);
if (self->buf != NULL) { if (self->buf != NULL) {
PyMem_Free(self->buf); PyMem_Free(self->buf);
self->buf = NULL; 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