|
1 |
| -// Demonstration of UB (Undefined Behavior) in handling of polymorphic pointers, |
2 |
| -// specifically: |
3 |
| -// https://github.com/pybind/pybind11/blob/30eb39ed79d1e2eeff15219ac00773034300a5e6/include/pybind11/cast.h#L229 |
4 |
| -// `return reinterpret_cast<V *&>(vh[0]);` |
5 |
| -// casts a `void` pointer to a `base`. The `void` pointer is obtained through |
6 |
| -// a `dynamic_cast` here: |
7 |
| -// https://github.com/pybind/pybind11/blob/30eb39ed79d1e2eeff15219ac00773034300a5e6/include/pybind11/cast.h#L852 |
8 |
| -// `return dynamic_cast<const void*>(src);` |
9 |
| -// The `dynamic_cast` is well-defined: |
10 |
| -// https://en.cppreference.com/w/cpp/language/dynamic_cast |
11 |
| -// 4) If expression is a pointer to a polymorphic type, and new-type |
12 |
| -// is a pointer to void, the result is a pointer to the most derived |
13 |
| -// object pointed or referenced by expression. |
14 |
| -// But the `reinterpret_cast` above is UB: `test_make_drvd_pass_base` in |
15 |
| -// `test_private_first_base.py` fails with a Segmentation Fault (Linux, |
16 |
| -// clang++ -std=c++17). |
17 |
| -// The only well-defined cast is back to a `drvd` pointer (`static_cast` can be |
18 |
| -// used), which can then safely be cast up to a `base` pointer. Note that |
19 |
| -// `test_make_drvd_up_cast_pass_drvd` passes because the `void` pointer is cast |
20 |
| -// to `drvd` pointer in this situation. |
| 1 | +// THIS ACTUALLY WORKS: |
| 2 | +// `py::multiple_inheritance()` was missing before. |
| 3 | +// https://github.com/pybind/pybind11/pull/2672#issuecomment-748543648 |
21 | 4 |
|
22 | 5 | #include "pybind11_tests.h"
|
23 | 6 |
|
@@ -49,7 +32,7 @@ inline int pass_drvd(const drvd* d) { return d->id(); }
|
49 | 32 |
|
50 | 33 | TEST_SUBMODULE(private_first_base, m) {
|
51 | 34 | py::class_<base>(m, "base");
|
52 |
| - py::class_<drvd, base>(m, "drvd"); |
| 35 | + py::class_<drvd, base>(m, "drvd", py::multiple_inheritance()); |
53 | 36 |
|
54 | 37 | m.def("make_drvd", make_drvd,
|
55 | 38 | py::return_value_policy::take_ownership);
|
|
0 commit comments