pybind11
pybind11 copied to clipboard
[BUG]: Using Virtual Inheritance and Multiple Inheritance Together Can Cause Crashes
Required prerequisites
- [X] Make sure you've read the documentation. Your issue may be addressed there.
- [X] Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- [ ] Consider asking first in the Gitter chat room or in a Discussion.
What version (or hash if on master) of pybind11 are you using?
2.13.6
Problem description
-
Environment:
- Windows 11
- Visual Studio 2019
- Python v3.12.4
- Pybind11 v2.13.6
-
Issue: When exporting a C++ class that uses virtual inheritance of multiple base classes through Pybind11, deleting the class object in Python code causes a crash.
-
Steps to Reproduce:
- Create a C++ class with virtual inheritance of multiple base classes.
- Export the class to Python using Pybind11.
- Create and delete an instance of the class in Python code.
-
Expected Behavior: The class object should be deleted without causing a crash.
-
Actual Behavior: Deleting the class object in Python code causes a crash, when del derived manual or exit test function.
-
Additional Information: Removing virtual inheritance from the C++ class resolves the issue.
Reproducible example code
#include <pybind11/pybind11.h>
#include <string>
#include <iostream>
namespace py = pybind11;
class Base1 {
public:
virtual ~Base1() = default;
virtual std::string greet_base1() = 0;
};
class Base2 {
public:
virtual ~Base2() = default;
virtual std::string greet_base2() = 0;
};
class Derived :
public Base1,
public Base2
{
public:
virtual ~Derived() = default;
virtual std::string greet_derived() = 0;
};
// create DerivedImpl class
class DerivedImpl : public Derived {
public:
virtual ~DerivedImpl() = default;
virtual std::string greet_derived() {
return "Hello derived";
}
virtual std::string greet_base1() {
return "Hello base1";
}
virtual std::string greet_base2() {
return "Hello base2";
}
private:
int z;
};
class DerivedFactory {
public:
static Derived* create_derived() {
return new DerivedImpl();
}
static void delete_derived(Derived* obj) {
return delete obj;
}
};
PYBIND11_MODULE(pybind_test, m) {
py::class_<Base1, std::unique_ptr<Base1, py::nodelete>>(m, "Base1")
.def("greet_base1", &Base1::greet_base1);
py::class_<Base2, std::unique_ptr<Base2, py::nodelete>>(m, "Base2")
.def("greet_base2", &Base2::greet_base2);
py::class_<Derived, Base1, Base2, std::unique_ptr<Derived, py::nodelete>>(m, "Derived")
.def("greet_derived", &Derived::greet_derived);
// create DerivedFactory class binding
py::class_<DerivedFactory>(m, "DerivedFactory")
.def_static("create_derived", &DerivedFactory::create_derived)
.def_static("delete_derived", &DerivedFactory::delete_derived);
}
import pybind_test
def test():
derived = pybind_test.DerivedFactory.create_derived()
print(derived.greet_derived())
print(derived.greet_base1())
print(derived.greet_base2())
pybind_test.DerivedFactory.delete_derived(derived)
# del derived
print("end of test")
if __name__ == "__main__":
test()
print("end of main")
Is this a regression? Put the last known working version here if it is.
Not a regression
have you tried using https://pybind11.readthedocs.io/en/stable/reference.html#_CPPv420multiple_inheritance