[Python-checkins] gh-104371: Fix calls to `__release_buffer__` while an exception is active (#104378)

kumaraditya303 webhook-mailer at python.org
Fri May 12 01:22:47 EDT 2023


https://github.com/python/cpython/commit/a0a98ddb31591357bead4694b21717cb4034924f
commit: a0a98ddb31591357bead4694b21717cb4034924f
branch: main
author: Jelle Zijlstra <jelle.zijlstra at gmail.com>
committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com>
date: 2023-05-12T05:22:40Z
summary:

gh-104371: Fix calls to `__release_buffer__` while an exception is active (#104378)

Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com>

files:
M Lib/test/test_buffer.py
M Objects/typeobject.c

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 @@ 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()
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);
 }
 
 /*



More information about the Python-checkins mailing list