Skip to content
Merged
21 changes: 21 additions & 0 deletions Lib/test/test_memoryio.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,10 +6,12 @@
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):
Expand DownExpand Up@@ -477,6 +479,25 @@ def test_getbuffer_empty(self):
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)
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
Fix crash during garbage collection of the :class:`io.BytesIO` buffer
object.
14 changes: 4 additions & 10 deletions Modules/_io/bytesio.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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;
}

Expand DownExpand Up@@ -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)
{
Expand All@@ -1116,15 +1111,14 @@ 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);
}

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},
Expand Down