mirror of
https://github.com/RYDE-WORK/pybind11.git
synced 2026-02-04 06:23:30 +08: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.
|
/// Deallocates an instance; via holder, if constructed; otherwise via operator delete.
|
||||||
static void dealloc(detail::value_and_holder &v_h) {
|
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()) {
|
if (v_h.holder_constructed()) {
|
||||||
v_h.holder<holder_type>().~holder_type();
|
v_h.holder<holder_type>().~holder_type();
|
||||||
v_h.set_holder_constructed(false);
|
v_h.set_holder_constructed(false);
|
||||||
|
|||||||
@ -379,6 +379,17 @@ TEST_SUBMODULE(class_, m) {
|
|||||||
// test_non_final_final
|
// test_non_final_final
|
||||||
struct IsNonFinalFinal {};
|
struct IsNonFinalFinal {};
|
||||||
py::class_<IsNonFinalFinal>(m, "IsNonFinalFinal", py::is_final());
|
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:
|
template <int N> class BreaksBase { public:
|
||||||
|
|||||||
@ -323,3 +323,9 @@ def test_non_final_final():
|
|||||||
class PyNonFinalFinalChild(m.IsNonFinalFinal):
|
class PyNonFinalFinalChild(m.IsNonFinalFinal):
|
||||||
pass
|
pass
|
||||||
assert str(exc_info.value).endswith("is not an acceptable base type")
|
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…
x
Reference in New Issue
Block a user