mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
Add error_scope to py::class_::dealloc() to protect destructor calls (#2342)
Fixes issue #1878
This commit is contained in:
parent
b8047245bb
commit
4d90f1a199
@ -1388,6 +1388,13 @@ private:
|
||||
|
||||
/// 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);
|
||||
|
@ -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:
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user