pybind11
pybind11 copied to clipboard
[BUG]: Accessing field of type shared_ptr crashes with double free
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.
- [X] 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.11.1
Problem description
Trying to access a field of type std::shared_ptr crashes the Python code immediately with double free or corruption.
This looks a bit like the reverse of https://github.com/pybind/pybind11/issues/1138 because the holder object should be a std::unique_ptr (at least the documentation says that this is the default holder object when no holder is specified) and the actual data instance is a std::shared_ptr. Not quite sure if the underlying cause is basically the same (=> duplicate) or if it makes sense to track it separately?
Reproducible example code
C++ code:
#include <cstdint>
#include <iostream>
#include <memory>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
struct Foo
{
int data;
Foo() : data{}
{
std::cout << "[Foo @ " << std::int64_t(this) << "] constructing instance\n";
}
Foo(Foo&& other) : data{other.data}
{
std::cout << "[Foo @ " << std::int64_t(this) << "] move-constructing instance\n";
}
// Make `Foo` move-only.
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
~Foo()
{
std::cout << "[Foo @ " << std::int64_t(this) << "] destructing instance\n";
}
};
struct Wrapper
{
std::shared_ptr<Foo> foo;
Wrapper() : foo{}
{
std::cout << "[Wrapper @ " << std::int64_t(this) << "] constructing instance\n";
}
Wrapper(Wrapper&& other) : foo{std::move(other.foo)}
{
std::cout << "[Wrapper @ " << std::int64_t(this) << "] move-constructing instance\n";
}
Wrapper(const Wrapper& other) : foo{other.foo}
{
std::cout << "[Wrapper @ " << std::int64_t(this) << "] copy-constructing instance\n";
}
~Wrapper()
{
std::cout << "[Wrapper @ " << std::int64_t(this) << "] destructing instance\n";
}
};
PYBIND11_MODULE(my_native_module, m)
{
py::class_<Foo>(m, "Foo") //
.def_readwrite("data", &Foo::data);
py::class_<Wrapper>(m, "Wrapper") //
.def_readonly("foo", &Wrapper::foo);
m.def("create_instance", []() {
Wrapper wrapper{};
wrapper.foo = std::make_shared<Foo>();
wrapper.foo->data = 42;
return wrapper;
});
}
Python usage code:
import my_native_module
wrapper = my_native_module.create_instance()
print(wrapper.foo)
Output:
[Wrapper @ 140732106222592] constructing instance
[Foo @ 32377264] constructing instance
[Wrapper @ 32376784] move-constructing instance
[Wrapper @ 140732106222592] destructing instance
<my_native_module.Foo object at 0x7f1aa7e509f0>
[Foo @ 32377264] destructing instance
double free or corruption (out)
[1] 488989 abort (core dumped) python ./test_from_python_bug_mre.py
Is this a regression? Put the last known working version here if it is.
Not a regression
Hello. Is this fixed with newest version 2.13.6 ?
It was for me an error of my code, where I needed to declare the kind of smart pointer to use.