Skip to content

Commit 43fea31

Browse files
serhiy-storchakacorona10
authored andcommitted
pythongh-111049: Fix crash during garbage collection of the BytesIO buffer object (pythonGH-111221)
1 parent 0776d9f commit 43fea31

File tree

3 files changed

+27
-10
lines changed

3 files changed

+27
-10
lines changed

Lib/test/test_memoryio.py

+21
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
import unittest
77
from test import support
88

9+
import gc
910
import io
1011
import _pyio as pyio
1112
import pickle
1213
import sys
14+
import weakref
1315

1416
class IntLike:
1517
def __init__(self, num):
@@ -477,6 +479,25 @@ def test_getbuffer_empty(self):
477479
buf2.release()
478480
memio.write(b'x')
479481

482+
def test_getbuffer_gc_collect(self):
483+
memio = self.ioclass(b"1234567890")
484+
buf = memio.getbuffer()
485+
memiowr = weakref.ref(memio)
486+
bufwr = weakref.ref(buf)
487+
# Create a reference loop.
488+
a = [buf]
489+
a.append(a)
490+
# The Python implementation emits an unraisable exception.
491+
with support.catch_unraisable_exception():
492+
del memio
493+
del buf
494+
del a
495+
# The C implementation emits an unraisable exception.
496+
with support.catch_unraisable_exception():
497+
gc.collect()
498+
self.assertIsNone(memiowr())
499+
self.assertIsNone(bufwr())
500+
480501
def test_read1(self):
481502
buf = self.buftype("1234567890")
482503
self.assertEqual(self.ioclass(buf).read1(), buf)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash during garbage collection of the :class:`io.BytesIO` buffer
2+
object.

Modules/_io/bytesio.c

+4-10
Original file line numberDiff line numberDiff line change
@@ -990,7 +990,9 @@ static int
990990
bytesio_clear(bytesio *self)
991991
{
992992
Py_CLEAR(self->dict);
993-
Py_CLEAR(self->buf);
993+
if (self->exports == 0) {
994+
Py_CLEAR(self->buf);
995+
}
994996
return 0;
995997
}
996998

@@ -1095,13 +1097,6 @@ bytesiobuf_releasebuffer(bytesiobuf *obj, Py_buffer *view)
10951097
b->exports--;
10961098
}
10971099

1098-
static int
1099-
bytesiobuf_clear(bytesiobuf *self)
1100-
{
1101-
Py_CLEAR(self->source);
1102-
return 0;
1103-
}
1104-
11051100
static int
11061101
bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg)
11071102
{
@@ -1116,15 +1111,14 @@ bytesiobuf_dealloc(bytesiobuf *self)
11161111
PyTypeObject *tp = Py_TYPE(self);
11171112
/* bpo-31095: UnTrack is needed before calling any callbacks */
11181113
PyObject_GC_UnTrack(self);
1119-
(void)bytesiobuf_clear(self);
1114+
Py_CLEAR(self->source);
11201115
tp->tp_free(self);
11211116
Py_DECREF(tp);
11221117
}
11231118

11241119
static PyType_Slot bytesiobuf_slots[] = {
11251120
{Py_tp_dealloc, bytesiobuf_dealloc},
11261121
{Py_tp_traverse, bytesiobuf_traverse},
1127-
{Py_tp_clear, bytesiobuf_clear},
11281122

11291123
// Buffer protocol
11301124
{Py_bf_getbuffer, bytesiobuf_getbuffer},

0 commit comments

Comments
 (0)