mirror of https://github.com/python/cpython
gh-104371: Fix calls to `__release_buffer__` while an exception is active (#104378)
Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
This commit is contained in:
parent
ac66cc17f2
commit
a0a98ddb31
|
@ -4749,6 +4749,19 @@ class TestPythonBufferProtocol(unittest.TestCase):
|
|||
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()
|
||||
|
|
|
@ -9117,6 +9117,12 @@ releasebuffer_maybe_call_super(PyObject *self, Py_buffer *buffer)
|
|||
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 *exc = PyErr_GetRaisedException();
|
||||
|
||||
PyObject *mv;
|
||||
bool is_buffer_wrapper = Py_TYPE(buffer->obj) == &_PyBufferWrapper_Type;
|
||||
if (is_buffer_wrapper) {
|
||||
|
@ -9124,7 +9130,7 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer)
|
|||
// __release_buffer__() that __buffer__() returned.
|
||||
PyBufferWrapper *bw = (PyBufferWrapper *)buffer->obj;
|
||||
if (bw->mv == NULL) {
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
mv = Py_NewRef(bw->mv);
|
||||
}
|
||||
|
@ -9134,7 +9140,7 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer)
|
|||
mv = PyMemoryView_FromBuffer(buffer);
|
||||
if (mv == NULL) {
|
||||
PyErr_WriteUnraisable(self);
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
// Set the memoryview to restricted mode, which forbids
|
||||
// users from saving any reference to the underlying buffer
|
||||
|
@ -9155,6 +9161,10 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer)
|
|||
PyObject_CallMethodNoArgs(mv, &_Py_ID(release));
|
||||
}
|
||||
Py_DECREF(mv);
|
||||
end:
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
PyErr_SetRaisedException(exc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue