Segfault on cleanup with multiple_inheritance and return_value_policy::reference
arjansomers opened this issue · 0 comments
arjansomers commented
I have a base (pure-abstract) interface that is extended by another (pure abstract) interface.
Then i have an implementation of the base interface and a implementation of the extended interface that derives the extended interface and the base implementation via virtual inheritance (diamond)
Now if i return a reference of type InterfaceExtened i can correctly use it.
If i however delete the object that is being referenced on the c++ side, then i get an error during program exit. I do not get such an error when doing the same using InterfaceBase.
I create file pybind11bug.cpp:
#include <pybind11/pybind11.h>
#include <memory>
#include <iostream>
class InterfaceBase {
public:
virtual ~InterfaceBase() = default;
virtual void foo() = 0;
};
class InterfaceExtended: public virtual InterfaceBase {
public:
virtual ~InterfaceExtended() = default;
virtual void bar() = 0;
};
class ImplementationBase: public virtual InterfaceBase {
public:
virtual void foo() { std::cout << "foo" << std::endl;};
};
class ImplementationExtended: public ImplementationBase, public InterfaceExtended {
public:
virtual void bar() { std::cout << "bar" << std::endl; };
};
class Helper {
public:
InterfaceBase& createBaseInstance() {
instanceBase.reset(new ImplementationBase());
return *instanceBase;
}
void deletebaseInstance() {
instanceBase.reset();
}
InterfaceExtended& createExtendedInstance() {
instanceExt.reset(new ImplementationExtended());
return *instanceExt;
}
void deleteBaseInstance() {
instanceBase.reset();
}
void deleteExtendedInstance() {
instanceExt.reset();
}
private:
std::unique_ptr<InterfaceBase> instanceBase;
std::unique_ptr<InterfaceExtended> instanceExt;
};
namespace py = pybind11;
PYBIND11_MODULE(example, m) {
py::class_<InterfaceBase>(m, "InterfaceBase")
.def("foo", &InterfaceBase::foo);
py::class_<InterfaceExtended, InterfaceBase>(m, "InterfaceExtended", py::multiple_inheritance())
.def("bar", &InterfaceExtended::bar);
py::class_<Helper>(m, "Helper")
.def(py::init())
.def("create_base_instance", &Helper::createBaseInstance, py::return_value_policy::reference)
.def("create_extended_instance", &Helper::createExtendedInstance, py::return_value_policy::reference)
.def("delete_base_instance", &Helper::deleteBaseInstance)
.def("delete_extended_instance", &Helper::deleteExtendedInstance);
}I compile with:
c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` pybind11bug.cpp -o example`python3-config --extension-suffix`Then i run:
import example
helper = example.Helper()
base = helper.create_base_instance()
ext = helper.create_extended_instance()
ext.foo()
ext.bar()
# deleting a return_value_policy::reference on c++ side
# for the base (non-virtual inheritance class) is fine
helper.delete_base_instance()
# deleting a return_value_policy::reference on c++ side
# for the extended (virtual inheritance class) generates a segfault on cleanup
# (when commenting out the next line there is no segfault)
helper.delete_extended_instance()