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

Possible memory issues when using shared_ptr as holder type #1937

Closed
lyskov opened this issue Sep 28, 2019 · 2 comments
Closed

Possible memory issues when using shared_ptr as holder type #1937

lyskov opened this issue Sep 28, 2019 · 2 comments

Comments

@lyskov
Copy link
Contributor

lyskov commented Sep 28, 2019

Dear Pybind11 developers, i would like to report a strange case which on a surface looks like a situation when C++ fail to retain ownership of classes defined in Python and derived from C++ base classes.

Below is a minimal example to reproduce this. Note that Python script have --bug command line argument which allow to trigger a bug. And if option is not supplied then code work as expected without any errors.

In short: issues seems to arise when derived class is created in C++ by a 'clone' method. It looks like after creation 'Python' portion of Snake class will get immediately deleted unless it explicitly stored in one of Python variables.

When --bug is supplied execution terminated with error message:

Snake.clone!
Traceback (most recent call last):
  File "inheritance-clone.py", line 34, in <module>
    example.clone_and_call_go(a)
RuntimeError: Tried to call pure virtual function "Animal::go"
#include <pybind11/pybind11.h>


class Animal {
public:
    virtual ~Animal() { }
    virtual std::string go(int n_times) = 0;

    virtual std::shared_ptr<Animal> clone() = 0;
};


std::string clone_and_call_go(std::shared_ptr<Animal> animal) {
    auto new_animal = animal->clone();
    return new_animal->go(3);
}


class PyAnimal : public Animal {
public:
    /* Inherit the constructors */
    using Animal::Animal;

    /* Trampoline (need one for each virtual function) */
    std::string go(int n_times) override {
        PYBIND11_OVERLOAD_PURE(
            std::string, /* Return type */
            Animal,      /* Parent class */
            go,          /* Name of function in C++ (must match Python name) */
            n_times      /* Argument(s) */
        );
    }

	std::shared_ptr<Animal> clone() override {
        PYBIND11_OVERLOAD_PURE(
            std::shared_ptr<Animal>,
            Animal,
            clone
        );
    }

};


namespace py = pybind11;

PYBIND11_MODULE(example, m) {

	py::class_<Animal, std::shared_ptr<Animal>, PyAnimal>(m, "Animal")
        .def(py::init<>())
        .def("go",    &Animal::go)
        .def("clone", &Animal::clone)
	;

	m.def("clone_and_call_go", &clone_and_call_go);

}
import argparse

import example

class Snake(example.Animal):
    def __init__(self, bug):
        #super().__init__()
        example.Animal.__init__(self)
        self.copies_ = []
        self.bug_ = bug

    def go(self, n_times):
        s = 'Snake.go({})'.format(n_times)
        print(s)
        return s

    def clone(self):
        print('Snake.clone!')
        copy = Snake(bug=self.bug_)
        if not self.bug_:
            self.copies_.append(copy)
        return copy



if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--bug", action="store_true", help="Disables the workaround, showcases the bug")
    args = parser.parse_args()


    a = Snake(args.bug)

    example.clone_and_call_go(a)
@lyskov
Copy link
Contributor Author

lyskov commented Sep 28, 2019

This issue might be possible duplicate of #1389

@EricCousineau-TRI
Copy link
Collaborator

Yup, most def. a duplicate of #1333 / #1389. Closing in lieu of #1333 as the tracking issue.

Feel free to reopen if you think this is a unique case!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants