Skip to content

Commit

Permalink
Add error_scope to py::class_::dealloc() to protect destructor calls (#…
Browse files Browse the repository at this point in the history
…2342)

Fixes issue #1878
  • Loading branch information
jbarlow83 authored Aug 1, 2020
1 parent b804724 commit 4d90f1a
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 0 deletions.
7 changes: 7 additions & 0 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,13 @@ class class_ : public detail::generic_type {

/// Deallocates an instance; via holder, if constructed; otherwise via operator delete.
static void dealloc(detail::value_and_holder &v_h) {
// We could be deallocating because we are cleaning up after a Python exception.
// If so, the Python error indicator will be set. We need to clear that before
// running the destructor, in case the destructor code calls more Python.
// If we don't, the Python API will exit with an exception, and pybind11 will
// throw error_already_set from the C++ destructor which is forbidden and triggers
// std::terminate().
error_scope scope;
if (v_h.holder_constructed()) {
v_h.holder<holder_type>().~holder_type();
v_h.set_holder_constructed(false);
Expand Down
11 changes: 11 additions & 0 deletions tests/test_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,17 @@ TEST_SUBMODULE(class_, m) {
// test_non_final_final
struct IsNonFinalFinal {};
py::class_<IsNonFinalFinal>(m, "IsNonFinalFinal", py::is_final());

struct PyPrintDestructor {
PyPrintDestructor() {}
~PyPrintDestructor() {
py::print("Print from destructor");
}
void throw_something() { throw std::runtime_error("error"); }
};
py::class_<PyPrintDestructor>(m, "PyPrintDestructor")
.def(py::init<>())
.def("throw_something", &PyPrintDestructor::throw_something);
}

template <int N> class BreaksBase { public:
Expand Down
6 changes: 6 additions & 0 deletions tests/test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,9 @@ def test_non_final_final():
class PyNonFinalFinalChild(m.IsNonFinalFinal):
pass
assert str(exc_info.value).endswith("is not an acceptable base type")


# https://github.com/pybind/pybind11/issues/1878
def test_exception_rvalue_abort():
with pytest.raises(RuntimeError):
m.PyPrintDestructor().throw_something()

0 comments on commit 4d90f1a

Please sign in to comment.