From 9623045b7b163caba1c2855fcbca692fbf216c38 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 22 Dec 2020 12:18:47 -0800 Subject: [PATCH] Additional demonstration of Undefined Behavior in handling of shared_ptr holder. --- tests/test_smart_ptr_private_first_base.cpp | 15 +++++++++++++-- tests/test_smart_ptr_private_first_base.py | 11 ++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/test_smart_ptr_private_first_base.cpp b/tests/test_smart_ptr_private_first_base.cpp index 862effb85..9ccc5edea 100644 --- a/tests/test_smart_ptr_private_first_base.cpp +++ b/tests/test_smart_ptr_private_first_base.cpp @@ -3,8 +3,12 @@ // https://github.com/pybind/pybind11/blob/30eb39ed79d1e2eeff15219ac00773034300a5e6/include/pybind11/cast.h#L235 // `return reinterpret_cast(vh[1]);` // indirectly casts a `shared_ptr` reference to a `shared_ptr`. -// `test_smart_ptr_private_first_base.py` fails with an AssertionError and -// a subsequent Segmentation Fault (Linux, clang++ -std=c++17). +// Similarly: +// https://github.com/pybind/pybind11/blob/30eb39ed79d1e2eeff15219ac00773034300a5e6/include/pybind11/pybind11.h#L1505 +// `init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr());` +// explictly casts a `shared_ptr` reference to a `shared_ptr`. +// Both tests in `test_smart_ptr_private_first_base.py` fail with a +// Segmentation Fault (Linux, clang++ -std=c++17). #include @@ -33,14 +37,21 @@ inline std::shared_ptr make_shared_drvd() { return std::shared_ptr(new drvd); } +inline std::shared_ptr make_shared_drvd_up_cast() { + return std::shared_ptr(new drvd); +} + inline int pass_shared_base(std::shared_ptr b) { return b->id(); } +inline int pass_shared_drvd(std::shared_ptr d) { return d->id(); } TEST_SUBMODULE(smart_ptr_private_first_base, m) { py::class_>(m, "base"); py::class_>(m, "drvd"); m.def("make_shared_drvd", make_shared_drvd); + m.def("make_shared_drvd_up_cast", make_shared_drvd_up_cast); m.def("pass_shared_base", pass_shared_base); + m.def("pass_shared_drvd", pass_shared_drvd); } } // namespace smart_ptr_private_first_base diff --git a/tests/test_smart_ptr_private_first_base.py b/tests/test_smart_ptr_private_first_base.py index 75ecfe6f1..a749a4665 100644 --- a/tests/test_smart_ptr_private_first_base.py +++ b/tests/test_smart_ptr_private_first_base.py @@ -3,7 +3,16 @@ import pytest from pybind11_tests import smart_ptr_private_first_base as m -def test_make_pass(): + +def test_make_drvd_pass_base(): d = m.make_shared_drvd() i = m.pass_shared_base(d) assert i == 200 + + +def test_make_drvd_up_cast_pass_drvd(): + b = m.make_shared_drvd_up_cast() + # the base return is up-cast immediately. + assert b.__class__.__name__ == "drvd" + i = m.pass_shared_drvd(b) + assert i == 200