Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]: Using Virtual Inheritance and Multiple Inheritance Together Can Cause Crashes #5479

Open
2 of 3 tasks
hzywlx opened this issue Dec 29, 2024 · 0 comments
Open
2 of 3 tasks
Labels
triage New bug, unverified

Comments

@hzywlx
Copy link

hzywlx commented Dec 29, 2024

Required prerequisites

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

@hzywlx hzywlx added the triage New bug, unverified label Dec 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage New bug, unverified
Projects
None yet
Development

No branches or pull requests

1 participant