Skip to content

Commit

Permalink
pythongh-104371: Fix calls to __release_buffer__ while an exception i…
Browse files Browse the repository at this point in the history
…s active
  • Loading branch information
JelleZijlstra committed May 11, 2023
1 parent fcd5fb4 commit 9abea7e
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 1 deletion.
13 changes: 13 additions & 0 deletions Lib/test/test_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4749,6 +4749,19 @@ def __buffer__(self, flags):
c.clear()
self.assertIs(c.buffer, None)

def test_release_buffer_with_exception_set(self):
class A:
def __buffer__(self, flags):
return memoryview(bytes(8))
def __release_buffer__(self, view):
pass

b = bytearray(8)
with memoryview(b):
# now b.extend will raise an exception due to exports
with self.assertRaises(BufferError):
b.extend(A())


if __name__ == "__main__":
unittest.main()
19 changes: 18 additions & 1 deletion Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -9115,8 +9115,9 @@ releasebuffer_maybe_call_super(PyObject *self, Py_buffer *buffer)
}

static void
releasebuffer_call_python(PyObject *self, Py_buffer *buffer)
releasebuffer_call_python_inner(PyObject *self, Py_buffer *buffer)
{
assert(!PyErr_Occurred());
PyObject *mv;
bool is_buffer_wrapper = Py_TYPE(buffer->obj) == &_PyBufferWrapper_Type;
if (is_buffer_wrapper) {
Expand Down Expand Up @@ -9157,6 +9158,22 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer)
Py_DECREF(mv);
}

static void
releasebuffer_call_python(PyObject *self, Py_buffer *buffer)
{
// bf_releasebuffer may be called while an exception is already active.
// We have no way to report additional errors up the stack, because
// this slot returns void, so we simply stash away the active exception
// and restore it after the call to Python returns.
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback);

releasebuffer_call_python_inner(self, buffer);
assert(!PyErr_Occurred());

PyErr_Restore(type, value, traceback);
}

/*
* bf_releasebuffer is very delicate, because we need to ensure that
* C bf_releasebuffer slots are called correctly (or we'll leak memory),
Expand Down

0 comments on commit 9abea7e

Please sign in to comment.