]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-111049: Fix crash during garbage collection of the BytesIO buffer object (GH-111221)
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 14 Dec 2023 10:04:23 +0000 (12:04 +0200)
committerGitHub <noreply@github.com>
Thu, 14 Dec 2023 10:04:23 +0000 (10:04 +0000)
Lib/test/test_memoryio.py
Misc/NEWS.d/next/Library/2023-10-23-18-42-26.gh-issue-111049.Ys7-o_.rst [new file with mode: 0644]
Modules/_io/bytesio.c

index 731299294e6877fdb7bceacc677b547fd93df0d8..8192502a40791b962723262b6eb3aee0a40f3b78 100644 (file)
@@ -6,10 +6,12 @@ BytesIO -- for bytes
 import unittest
 from test import support
 
+import gc
 import io
 import _pyio as pyio
 import pickle
 import sys
+import weakref
 
 class IntLike:
     def __init__(self, num):
@@ -477,6 +479,25 @@ class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase):
         buf2.release()
         memio.write(b'x')
 
+    def test_getbuffer_gc_collect(self):
+        memio = self.ioclass(b"1234567890")
+        buf = memio.getbuffer()
+        memiowr = weakref.ref(memio)
+        bufwr = weakref.ref(buf)
+        # Create a reference loop.
+        a = [buf]
+        a.append(a)
+        # The Python implementation emits an unraisable exception.
+        with support.catch_unraisable_exception():
+            del memio
+        del buf
+        del a
+        # The C implementation emits an unraisable exception.
+        with support.catch_unraisable_exception():
+            gc.collect()
+        self.assertIsNone(memiowr())
+        self.assertIsNone(bufwr())
+
     def test_read1(self):
         buf = self.buftype("1234567890")
         self.assertEqual(self.ioclass(buf).read1(), buf)
diff --git a/Misc/NEWS.d/next/Library/2023-10-23-18-42-26.gh-issue-111049.Ys7-o_.rst b/Misc/NEWS.d/next/Library/2023-10-23-18-42-26.gh-issue-111049.Ys7-o_.rst
new file mode 100644 (file)
index 0000000..b1de348
--- /dev/null
@@ -0,0 +1,2 @@
+Fix crash during garbage collection of the :class:`io.BytesIO` buffer
+object.
index 16b8ac600ace79fc60376c9ff802ec5e9158f0ba..4a15c8e841f25fa923214f6bcca602a0b7847841 100644 (file)
@@ -990,7 +990,9 @@ static int
 bytesio_clear(bytesio *self)
 {
     Py_CLEAR(self->dict);
-    Py_CLEAR(self->buf);
+    if (self->exports == 0) {
+        Py_CLEAR(self->buf);
+    }
     return 0;
 }
 
@@ -1095,13 +1097,6 @@ bytesiobuf_releasebuffer(bytesiobuf *obj, Py_buffer *view)
     b->exports--;
 }
 
-static int
-bytesiobuf_clear(bytesiobuf *self)
-{
-    Py_CLEAR(self->source);
-    return 0;
-}
-
 static int
 bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg)
 {
@@ -1116,7 +1111,7 @@ bytesiobuf_dealloc(bytesiobuf *self)
     PyTypeObject *tp = Py_TYPE(self);
     /* bpo-31095: UnTrack is needed before calling any callbacks */
     PyObject_GC_UnTrack(self);
-    (void)bytesiobuf_clear(self);
+    Py_CLEAR(self->source);
     tp->tp_free(self);
     Py_DECREF(tp);
 }
@@ -1124,7 +1119,6 @@ bytesiobuf_dealloc(bytesiobuf *self)
 static PyType_Slot bytesiobuf_slots[] = {
     {Py_tp_dealloc, bytesiobuf_dealloc},
     {Py_tp_traverse, bytesiobuf_traverse},
-    {Py_tp_clear, bytesiobuf_clear},
 
     // Buffer protocol
     {Py_bf_getbuffer, bytesiobuf_getbuffer},