Skip to content

Commit 47b81af

Browse files
committed
Additional demonstration of Undefined Behavior in handling of shared_ptr holder.
1 parent e0207d6 commit 47b81af

File tree

2 files changed

+23
-3
lines changed

2 files changed

+23
-3
lines changed

tests/test_smart_ptr_private_first_base.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
// https://github.com/pybind/pybind11/blob/30eb39ed79d1e2eeff15219ac00773034300a5e6/include/pybind11/cast.h#L235
44
// `return reinterpret_cast<H &>(vh[1]);`
55
// 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).
6+
// Similarly:
7+
// https://github.com/pybind/pybind11/blob/30eb39ed79d1e2eeff15219ac00773034300a5e6/include/pybind11/pybind11.h#L1505
8+
// `init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr<type>());`
9+
// explictly casts a `shared_ptr<base>` reference to a `shared_ptr<drvd>`.
10+
// Both tests in `test_smart_ptr_private_first_base.py` fail with a
11+
// Segmentation Fault (Linux, clang++ -std=c++17).
812

913
#include <memory>
1014

@@ -33,14 +37,21 @@ inline std::shared_ptr<drvd> make_shared_drvd() {
3337
return std::shared_ptr<drvd>(new drvd);
3438
}
3539

40+
inline std::shared_ptr<base> make_shared_drvd_up_cast() {
41+
return std::shared_ptr<base>(new drvd);
42+
}
43+
3644
inline int pass_shared_base(std::shared_ptr<base> b) { return b->id(); }
45+
inline int pass_shared_drvd(std::shared_ptr<drvd> d) { return d->id(); }
3746

3847
TEST_SUBMODULE(smart_ptr_private_first_base, m) {
3948
py::class_<base, std::shared_ptr<base>>(m, "base");
4049
py::class_<drvd, base, std::shared_ptr<drvd>>(m, "drvd");
4150

4251
m.def("make_shared_drvd", make_shared_drvd);
52+
m.def("make_shared_drvd_up_cast", make_shared_drvd_up_cast);
4353
m.def("pass_shared_base", pass_shared_base);
54+
m.def("pass_shared_drvd", pass_shared_drvd);
4455
}
4556

4657
} // namespace smart_ptr_private_first_base

tests/test_smart_ptr_private_first_base.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,16 @@
33

44
from pybind11_tests import smart_ptr_private_first_base as m
55

6-
def test_make_pass():
6+
7+
def test_make_drvd_pass_base():
78
d = m.make_shared_drvd()
89
i = m.pass_shared_base(d)
910
assert i == 200
11+
12+
13+
def test_make_drvd_up_cast_pass_drvd():
14+
b = m.make_shared_drvd_up_cast()
15+
# the base return is up-cast immediately.
16+
assert b.__class__.__name__ == "drvd"
17+
i = m.pass_shared_drvd(b)
18+
assert i == 200

0 commit comments

Comments
 (0)