Bound C++ object contains "garbage" after being copied in Python
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 18k
- Forks
- 2.3k
- Avg merge
- 5d 17h
- Merged PRs (30d)
- 10
Description
Issue description
This is caused because this (in bound object) becomes an invalid pointer after copying the object in Python using copy.copy.
Reproducible example code
#include <pybind11/pybind11.h>
#include <memory>
#include <iostream>
namespace py = pybind11;
class CopyTest {
public:
CopyTest(size_t number) : number(number) {
std::cerr << "[CONSTRUCTOR of CopyTest at " << this << "; number = " << this->number << "]\n";
}
~CopyTest() {
std::cerr << "[DESTRUCTOR of CopyTest at " << this << "; number = " << this->number << "]\n";
}
CopyTest() = delete;
CopyTest(CopyTest const&) = delete;
size_t get_number() const { return number; }
size_t get_memory_location() const { return reinterpret_cast<size_t>(this); }
protected:
size_t number;
};
std::shared_ptr<CopyTest> create_copy_test(size_t number) {
return std::make_shared<CopyTest>(number);
}
PYBIND11_MODULE(_pb11pg, m) {
m.doc() = "pybind11 testing module";
py::class_<CopyTest, std::shared_ptr<CopyTest>>(m, "CopyTest")
.def_property_readonly("number", &CopyTest::get_number)
.def_property_readonly("memory_location", &CopyTest::get_memory_location);
m.def("create_copy_test", &create_copy_test);
}
def test_copy_error():
import _pb11pg
x = _pb11pg.create_copy_test(424242)
memory_location = x.memory_location
assert x.number == 424242
import copy
x_copy = copy.copy(x)
copy_memory_location = x_copy.memory_location
assert x_copy.number == 424242
assert copy_memory_location == memory_location
Note that the copied object now contains "garbage":
> assert x_copy.number == 424242
E assert 287762808833 == 424242
E + where 287762808833 = <_pb11pg.CopyTest object at 0x0000012AAAFE7570>.number
and the this pointer is changed:
> assert copy_memory_location == memory_location
E assert 1663910680432 == 1663870278992
I've noticed that the constructor and destructor are called only once, and no copy-constructor or default-constructor are called, as I've "removed" them with = delete.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by building the supplied C++ binding and running the provided Python test_copy_error reproduction with copy.copy. Trace pybind11's handling of copying bound objects and their this pointers. Done means the copied object preserves the original memory location and number value without invalid object state.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- api
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100