|
| 1 | +// Demonstration of Undefined Behavior in handling of shared_ptr holder, |
| 2 | +// specifically: |
| 3 | +// https://github.com/pybind/pybind11/blob/30eb39ed79d1e2eeff15219ac00773034300a5e6/include/pybind11/cast.h#L235 |
| 4 | +// `return reinterpret_cast<H &>(vh[1]);` |
| 5 | +// indirectly casts a `shared_ptr<drvd>` reference to a `shared_ptr<base>`. |
| 6 | +// `test_smart_ptr_private_first_base.py` fails with an AssertionError and |
| 7 | +// a subsequent Segmentation Fault (Linux, clang++ -std=c++17). |
| 8 | + |
| 9 | +#include <memory> |
| 10 | + |
| 11 | +#include "pybind11_tests.h" |
| 12 | + |
| 13 | +namespace pybind11_tests { |
| 14 | +namespace smart_ptr_private_first_base { |
| 15 | + |
| 16 | +struct base { |
| 17 | + base() : base_id(100) {} |
| 18 | + virtual ~base() = default; |
| 19 | + virtual int id() const { return base_id; } |
| 20 | + int base_id; |
| 21 | +}; |
| 22 | + |
| 23 | +struct private_first_base { // Any class with a virtual function will do. |
| 24 | + virtual void some_other_virtual_function() const {} |
| 25 | + virtual ~private_first_base() = default; |
| 26 | +}; |
| 27 | + |
| 28 | +struct drvd : private private_first_base, public base { |
| 29 | + int id() const override { return 2 * base_id; } |
| 30 | +}; |
| 31 | + |
| 32 | +inline std::shared_ptr<drvd> make_shared_drvd() { |
| 33 | + return std::shared_ptr<drvd>(new drvd); |
| 34 | +} |
| 35 | + |
| 36 | +inline int pass_shared_base(std::shared_ptr<base> b) { return b->id(); } |
| 37 | + |
| 38 | +TEST_SUBMODULE(smart_ptr_private_first_base, m) { |
| 39 | + py::class_<base, std::shared_ptr<base>>(m, "base"); |
| 40 | + py::class_<drvd, base, std::shared_ptr<drvd>>(m, "drvd"); |
| 41 | + |
| 42 | + m.def("make_shared_drvd", make_shared_drvd); |
| 43 | + m.def("pass_shared_base", pass_shared_base); |
| 44 | +} |
| 45 | + |
| 46 | +} // namespace smart_ptr_private_first_base |
| 47 | +} // namespace pybind11_tests |
0 commit comments