From 146695a904526adc70c97615f7c395c4b3115c18 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Fri, 25 Mar 2022 10:55:13 -0400 Subject: [PATCH] fix: better exception and error handling for capsules (#3825) * Make capsule errors better match python --- include/pybind11/numpy.h | 3 ++- include/pybind11/pytypes.h | 32 +++++++++++++++++++------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 07dea21b4..7624c9fbf 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -1288,7 +1288,8 @@ public: static pybind11::dtype dtype() { list shape; array_info::append_extents(shape); - return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape)); + return pybind11::dtype::from_args( + pybind11::make_tuple(base_descr::dtype(), std::move(shape))); } }; diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index e54941485..b9ec8af4e 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1574,7 +1574,7 @@ public: void (*destructor)(PyObject *) = nullptr) : object(PyCapsule_New(const_cast(value), name, destructor), stolen_t{}) { if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); + throw error_already_set(); } } @@ -1582,34 +1582,42 @@ public: capsule(const void *value, void (*destruct)(PyObject *)) : object(PyCapsule_New(const_cast(value), nullptr, destruct), stolen_t{}) { if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); + throw error_already_set(); } } capsule(const void *value, void (*destructor)(void *)) { m_ptr = PyCapsule_New(const_cast(value), nullptr, [](PyObject *o) { auto destructor = reinterpret_cast(PyCapsule_GetContext(o)); + if (destructor == nullptr) { + if (PyErr_Occurred()) { + throw error_already_set(); + } + pybind11_fail("Unable to get capsule context"); + } void *ptr = PyCapsule_GetPointer(o, nullptr); + if (ptr == nullptr) { + throw error_already_set(); + } destructor(ptr); }); - if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); - } - - if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) { - pybind11_fail("Could not set capsule context!"); + if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) { + throw error_already_set(); } } explicit capsule(void (*destructor)()) { m_ptr = PyCapsule_New(reinterpret_cast(destructor), nullptr, [](PyObject *o) { auto destructor = reinterpret_cast(PyCapsule_GetPointer(o, nullptr)); + if (destructor == nullptr) { + throw error_already_set(); + } destructor(); }); if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); + throw error_already_set(); } } @@ -1624,8 +1632,7 @@ public: const auto *name = this->name(); T *result = static_cast(PyCapsule_GetPointer(m_ptr, name)); if (!result) { - PyErr_Clear(); - pybind11_fail("Unable to extract capsule contents!"); + throw error_already_set(); } return result; } @@ -1633,8 +1640,7 @@ public: /// Replaces a capsule's pointer *without* calling the destructor on the existing one. void set_pointer(const void *value) { if (PyCapsule_SetPointer(m_ptr, const_cast(value)) != 0) { - PyErr_Clear(); - pybind11_fail("Could not set capsule pointer"); + throw error_already_set(); } }