bpo-37054, _pyio: Fix BytesIO and TextIOWrapper __del__() (GH-13601)
authorVictor Stinner <vstinner@redhat.com>
Mon, 27 May 2019 23:44:21 +0000 (01:44 +0200)
committerGitHub <noreply@github.com>
Mon, 27 May 2019 23:44:21 +0000 (01:44 +0200)
Fix destructor _pyio.BytesIO and _pyio.TextIOWrapper: initialize
their _buffer attribute as soon as possible (in the class body),
because it's used by __del__() which calls close().

Lib/_pyio.py
Misc/NEWS.d/next/Library/2019-05-28-01-06-44.bpo-37054.sLULGQ.rst [new file with mode: 0644]

index 5baca4df82ff44607310789ab3dc5d3c4a4e658b..43c24342ad6162ce97bc93a20fd105a3500c5f1e 100644 (file)
@@ -873,6 +873,10 @@ class BytesIO(BufferedIOBase):
 
     """Buffered I/O implementation using an in-memory bytes buffer."""
 
+    # Initialize _buffer as soon as possible since it's used by __del__()
+    # which calls close()
+    _buffer = None
+
     def __init__(self, initial_bytes=None):
         buf = bytearray()
         if initial_bytes is not None:
@@ -900,7 +904,8 @@ class BytesIO(BufferedIOBase):
         return memoryview(self._buffer)
 
     def close(self):
-        self._buffer.clear()
+        if self._buffer is not None:
+            self._buffer.clear()
         super().close()
 
     def read(self, size=-1):
@@ -1970,6 +1975,10 @@ class TextIOWrapper(TextIOBase):
 
     _CHUNK_SIZE = 2048
 
+    # Initialize _buffer as soon as possible since it's used by __del__()
+    # which calls close()
+    _buffer = None
+
     # The write_through argument has no effect here since this
     # implementation always writes through.  The argument is present only
     # so that the signature can match the signature of the C version.
diff --git a/Misc/NEWS.d/next/Library/2019-05-28-01-06-44.bpo-37054.sLULGQ.rst b/Misc/NEWS.d/next/Library/2019-05-28-01-06-44.bpo-37054.sLULGQ.rst
new file mode 100644 (file)
index 0000000..9a2433a
--- /dev/null
@@ -0,0 +1,3 @@
+Fix destructor :class:`_pyio.BytesIO` and :class:`_pyio.TextIOWrapper`:
+initialize their ``_buffer`` attribute as soon as possible (in the class
+body), because it's used by ``__del__()`` which calls ``close()``.