Skip to content

Commit b7fb7a4

Browse files
committed
Fix buffer classes using super()
1 parent 4cd95dc commit b7fb7a4

File tree

5 files changed

+45
-5
lines changed

5 files changed

+45
-5
lines changed

Include/internal/pycore_memoryobject.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ extern "C" {
99
#endif
1010

1111
PyObject *
12-
PyMemoryView_FromObjectAndFlags(PyObject *v, int flags);
12+
_PyMemoryView_FromBufferProc(PyObject *v, int flags,
13+
getbufferproc bufferproc);
1314

1415
#ifdef __cplusplus
1516
}

Lib/test/test_buffer.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4579,6 +4579,15 @@ def test_c_buffer(self):
45794579
buf.__release_buffer__(mv)
45804580
self.assertEqual(buf.references, 0)
45814581

4582+
def test_inheritance(self):
4583+
class A(bytearray):
4584+
def __buffer__(self, flags):
4585+
return super().__buffer__(flags)
4586+
4587+
a = A(b"hello")
4588+
mv = memoryview(a)
4589+
self.assertEqual(mv.tobytes(), b"hello")
4590+
45824591

45834592
if __name__ == "__main__":
45844593
unittest.main()

Objects/bytearrayobject.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ static void
6161
bytearray_releasebuffer(PyByteArrayObject *obj, Py_buffer *view)
6262
{
6363
obj->ob_exports--;
64+
assert(obj->ob_exports >= 0);
6465
}
6566

6667
static int

Objects/memoryobject.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ PyMemoryView_FromBuffer(const Py_buffer *info)
781781
using the given flags.
782782
If the object is a memoryview, the new memoryview must be registered
783783
with the same managed buffer. Otherwise, a new managed buffer is created. */
784-
PyObject *
784+
static PyObject *
785785
PyMemoryView_FromObjectAndFlags(PyObject *v, int flags)
786786
{
787787
_PyManagedBufferObject *mbuf;
@@ -806,6 +806,30 @@ PyMemoryView_FromObjectAndFlags(PyObject *v, int flags)
806806
Py_TYPE(v)->tp_name);
807807
return NULL;
808808
}
809+
810+
/* Create a memoryview from an object that implements the buffer protocol,
811+
using the given flags.
812+
If the object is a memoryview, the new memoryview must be registered
813+
with the same managed buffer. Otherwise, a new managed buffer is created. */
814+
PyObject *
815+
_PyMemoryView_FromBufferProc(PyObject *v, int flags, getbufferproc bufferproc)
816+
{
817+
_PyManagedBufferObject *mbuf = mbuf_alloc();
818+
if (mbuf == NULL)
819+
return NULL;
820+
821+
int res = bufferproc(v, &mbuf->master, flags);
822+
if (res < 0) {
823+
mbuf->master.obj = NULL;
824+
Py_DECREF(mbuf);
825+
return NULL;
826+
}
827+
828+
PyObject *ret = mbuf_add_view(mbuf, NULL);
829+
Py_DECREF(mbuf);
830+
return ret;
831+
}
832+
809833
/* Create a memoryview from an object that implements the buffer protocol.
810834
If the object is a memoryview, the new memoryview must be registered
811835
with the same managed buffer. Otherwise, a new managed buffer is created. */

Objects/typeobject.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include "pycore_symtable.h" // _Py_Mangle()
77
#include "pycore_dict.h" // _PyDict_KeysSize()
88
#include "pycore_initconfig.h" // _PyStatus_OK()
9-
#include "pycore_memoryobject.h" // PyMemoryView_FromObjectAndFlags()
9+
#include "pycore_memoryobject.h" // _PyMemoryView_FromBufferProc()
1010
#include "pycore_moduleobject.h" // _PyModule_GetDef()
1111
#include "pycore_object.h" // _PyType_HasFeature()
1212
#include "pycore_long.h" // _PyLong_IsNegative()
@@ -56,6 +56,8 @@ typedef struct PySlot_Offset {
5656
short slot_offset;
5757
} PySlot_Offset;
5858

59+
static void
60+
slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer);
5961

6062
static PyObject *
6163
slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
@@ -8078,7 +8080,8 @@ wrap_buffer(PyObject *self, PyObject *args, void *wrapped)
80788080
return NULL;
80798081
}
80808082

8081-
return PyMemoryView_FromObjectAndFlags(self, Py_SAFE_DOWNCAST(flags, Py_ssize_t, int));
8083+
return _PyMemoryView_FromBufferProc(self, Py_SAFE_DOWNCAST(flags, Py_ssize_t, int),
8084+
(getbufferproc)wrapped);
80828085
}
80838086

80848087
static PyObject *
@@ -8980,8 +8983,10 @@ bufferwrapper_releasebuf(PyObject *self, Py_buffer *view)
89808983

89818984
assert(PyMemoryView_Check(bw->mv));
89828985
Py_TYPE(bw->mv)->tp_as_buffer->bf_releasebuffer(bw->mv, view);
8986+
// We only need to call bf_releasebuffer if it's a Python function. If it's a C
8987+
// bf_releasebuf, it will be called when the memoryview is released.
89838988
if (Py_TYPE(bw->obj)->tp_as_buffer != NULL
8984-
&& Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer != NULL) {
8989+
&& Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer == slot_bf_releasebuffer) {
89858990
Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer(bw->obj, view);
89868991
}
89878992
}

0 commit comments

Comments
 (0)