From 7fcf8202584e06899718b28f90caeae46f0af098 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 6 Nov 2024 19:01:20 -0500 Subject: [PATCH 1/2] Use std::unique_ptr in pybind11_getbuffer --- include/pybind11/detail/class.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index 6f87f7d4c1..90318dbdca 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -583,9 +583,9 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla return -1; } std::memset(view, 0, sizeof(Py_buffer)); - buffer_info *info = nullptr; + std::unique_ptr info = nullptr; try { - info = tinfo->get_buffer(obj, tinfo->get_buffer_data); + info.reset(tinfo->get_buffer(obj, tinfo->get_buffer_data)); } catch (...) { try_translate_exceptions(); raise_from(PyExc_BufferError, "Error getting buffer"); @@ -596,7 +596,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla } if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) { - delete info; // view->obj = nullptr; // Was just memset to 0, so not necessary set_error(PyExc_BufferError, "Writable buffer requested for readonly storage"); return -1; @@ -605,7 +604,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla // Fill in all the information, and then downgrade as requested by the caller, or raise an // error if that's not possible. view->obj = obj; - view->internal = info; view->buf = info->ptr; view->itemsize = info->itemsize; view->len = view->itemsize; @@ -624,7 +622,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla if ((flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) { if (PyBuffer_IsContiguous(view, 'C') == 0) { std::memset(view, 0, sizeof(Py_buffer)); - delete info; set_error(PyExc_BufferError, "C-contiguous buffer requested for discontiguous storage"); return -1; @@ -632,7 +629,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla } else if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) { if (PyBuffer_IsContiguous(view, 'F') == 0) { std::memset(view, 0, sizeof(Py_buffer)); - delete info; set_error(PyExc_BufferError, "Fortran-contiguous buffer requested for discontiguous storage"); return -1; @@ -640,7 +636,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla } else if ((flags & PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS) { if (PyBuffer_IsContiguous(view, 'A') == 0) { std::memset(view, 0, sizeof(Py_buffer)); - delete info; set_error(PyExc_BufferError, "Contiguous buffer requested for discontiguous storage"); return -1; } @@ -650,7 +645,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla // https://docs.python.org/3/c-api/buffer.html#contiguity-requests if (PyBuffer_IsContiguous(view, 'C') == 0) { std::memset(view, 0, sizeof(Py_buffer)); - delete info; set_error(PyExc_BufferError, "C-contiguous buffer requested for discontiguous storage"); return -1; @@ -665,6 +659,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla } } + view->internal = info.release(); Py_INCREF(view->obj); return 0; } From ef01e176822220fb2dc20ac85e75cbb4859e53a0 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 7 Nov 2024 19:32:44 -0500 Subject: [PATCH 2/2] Move final assignment later --- include/pybind11/detail/class.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index 90318dbdca..88e6d60a98 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -603,8 +603,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla // Fill in all the information, and then downgrade as requested by the caller, or raise an // error if that's not possible. - view->obj = obj; - view->buf = info->ptr; view->itemsize = info->itemsize; view->len = view->itemsize; for (auto s : info->shape) { @@ -659,7 +657,11 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla } } + // Set these after all checks so they don't leak out into the caller, and can be automatically + // cleaned up on error. + view->buf = info->ptr; view->internal = info.release(); + view->obj = obj; Py_INCREF(view->obj); return 0; }