Skip to content

Commit 7b63b9f

Browse files
committed
Adding py::multiple_inheritance() fixes the test.
1 parent faec6cb commit 7b63b9f

File tree

1 file changed

+4
-21
lines changed

1 file changed

+4
-21
lines changed

pybind11_tests/test_private_first_base.cpp

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,6 @@
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
214

225
#include "pybind11_tests.h"
236

@@ -49,7 +32,7 @@ inline int pass_drvd(const drvd* d) { return d->id(); }
4932

5033
TEST_SUBMODULE(private_first_base, m) {
5134
py::class_<base>(m, "base");
52-
py::class_<drvd, base>(m, "drvd");
35+
py::class_<drvd, base>(m, "drvd", py::multiple_inheritance());
5336

5437
m.def("make_drvd", make_drvd,
5538
py::return_value_policy::take_ownership);

0 commit comments

Comments
 (0)