From: Jelle Zijlstra Date: Fri, 12 May 2023 05:22:40 +0000 (-0700) Subject: gh-104371: Fix calls to `__release_buffer__` while an exception is active (#104378) X-Git-Tag: v3.12.0b1~156 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a0a98ddb31591357bead4694b21717cb4034924f;p=thirdparty%2FPython%2Fcpython.git gh-104371: Fix calls to `__release_buffer__` while an exception is active (#104378) Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 2c65ae811481..94fc9d4436b7 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -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() diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f1745c919673..f40e197f8c23 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -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); } /*