diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 256775bf7..5def56694 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -71,36 +71,22 @@ bool odr_guard_impl(const std::type_index & it_ti, const std::uint64_t& tc_id) { template struct type_caster_odr_guard : type_caster { - type_caster_odr_guard() { - odr_guard_hook = !!odr_guard_hook; - } - - // type_caster_odr_guard(const type_caster_odr_guard &) = default; - // type_caster_odr_guard(type_caster_odr_guard &&) = default; - - template - static handle cast(CType &&src, return_value_policy policy, handle parent, - Arg &&...arg) { - odr_guard_hook = !!odr_guard_hook; - return type_caster::cast(std::forward(src), policy, parent, - std::forward(arg)...); - } - - static bool odr_guard_hook; + static int translation_unit_local; }; template -bool type_caster_odr_guard::odr_guard_hook = [](){ - return odr_guard_impl( +int type_caster_odr_guard::translation_unit_local = [](){ + odr_guard_impl( std::type_index(typeid(IntrinsicType)), type_caster::universally_unique_identifier); + return 0; }(); +} // namespace + template using make_caster = type_caster_odr_guard>; -} // namespace - template struct type_uses_smart_holder_type_caster { static constexpr bool value @@ -110,11 +96,15 @@ struct type_uses_smart_holder_type_caster { // Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T template typename make_caster::template cast_op_type cast_op(make_caster &caster) { // LOOOK + if (make_caster::translation_unit_local) { + } return caster.operator typename make_caster::template cast_op_type(); } template typename make_caster::template cast_op_type::type> cast_op(make_caster &&caster) { // LOOOK + if (make_caster::translation_unit_local) { + } return std::move(caster).operator typename make_caster:: template cast_op_type::type>(); } @@ -1118,6 +1108,8 @@ type_caster &load_type(type_caster &conv, const handle &ha // Wrapper around the above that also constructs and returns a type_caster template make_caster load_type(const handle &handle) { + if (make_caster::translation_unit_local) { + } make_caster conv; load_type(conv, handle); return conv; @@ -1155,6 +1147,8 @@ object cast(T &&value, : std::is_lvalue_reference::value ? return_value_policy::copy : return_value_policy::move; } + if (detail::make_caster::translation_unit_local) { + } return reinterpret_steal( detail::make_caster::cast(std::forward(value), policy, parent)); } @@ -1255,6 +1249,8 @@ using override_caster_t = conditional_t enable_if_t::value, T> cast_ref(object &&o, make_caster &caster) { + if (make_caster::translation_unit_local) { + } return cast_op(load_type(caster, o)); } template @@ -1366,6 +1362,8 @@ private: type(type_id()) #endif { + if (detail::make_caster::translation_unit_local) { + } // Workaround! See: // https://github.com/pybind/pybind11/issues/2336 // https://github.com/pybind/pybind11/pull/2685#issuecomment-731286700 @@ -1596,6 +1594,8 @@ public: private: template void process(list &args_list, T &&x) { + if (make_caster::translation_unit_local) { + } auto o = reinterpret_steal( detail::make_caster::cast(std::forward(x), policy, {})); if (!o) { @@ -1740,6 +1740,8 @@ handle type::handle_of() { detail::type_uses_smart_holder_type_caster>::value, "py::type::of only supports the case where T is a registered C++ types."); + if (detail::make_caster::translation_unit_local) { + } return detail::get_type_handle(typeid(T), true); } diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 351b28d6c..af96dec4d 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -349,6 +349,8 @@ struct variant_caster_visitor { template result_type operator()(T &&src) const { + if (make_caster::translation_unit_local) { + } return make_caster::cast(std::forward(src), policy, parent); } }; diff --git a/tests/test_odr_guard_1.cpp b/tests/test_odr_guard_1.cpp index 035984b68..fb0703e14 100644 --- a/tests/test_odr_guard_1.cpp +++ b/tests/test_odr_guard_1.cpp @@ -1,22 +1,18 @@ #include "pybind11_tests.h" -#define USE_MRC_AAA -#ifdef USE_MRC_AAA namespace mrc_ns { // minimal real caster struct type_mrc { int value = -9999; }; -template struct minimal_real_caster { static constexpr auto name = py::detail::const_name(); - static std::int32_t odr_guard; // WANTED: ASAN detect_odr_violation + static constexpr std::uint64_t universally_unique_identifier = 1000; static py::handle cast(type_mrc const &src, py::return_value_policy /*policy*/, py::handle /*parent*/) { - odr_guard++; // Just to make sure it is used. - return py::int_(src.value + 1010).release(); // Actual ODR violation. + return py::int_(src.value + 1010).release(); // ODR violation. } // Maximizing simplicity. This will go terribly wrong for other arg types. @@ -26,7 +22,7 @@ struct minimal_real_caster { // NOLINTNEXTLINE(google-explicit-constructor) operator type_mrc const &() { static type_mrc obj; - obj.value = 11; // Actual ODR violation. + obj.value = 11; // ODR violation. return obj; } @@ -36,25 +32,16 @@ struct minimal_real_caster { } }; -template -std::int32_t minimal_real_caster::odr_guard = 0; - } // namespace mrc_ns namespace pybind11 { namespace detail { template <> -struct type_caster : mrc_ns::minimal_real_caster<> {}; +struct type_caster : mrc_ns::minimal_real_caster {}; } // namespace detail } // namespace pybind11 -#endif TEST_SUBMODULE(odr_guard_1, m) { -#ifdef USE_MRC_AAA - m.def("sizeof_mrc_odr_guard", - []() { return sizeof(mrc_ns::minimal_real_caster<>::odr_guard); }); m.def("type_mrc_to_python", []() { return mrc_ns::type_mrc{101}; }); m.def("type_mrc_from_python", [](const mrc_ns::type_mrc &obj) { return obj.value + 100; }); - m.def("mrc_odr_guard", []() { return mrc_ns::minimal_real_caster<>::odr_guard; }); -#endif } diff --git a/tests/test_odr_guard_1.py b/tests/test_odr_guard_1.py index fefe6cde4..398b4ce52 100644 --- a/tests/test_odr_guard_1.py +++ b/tests/test_odr_guard_1.py @@ -3,32 +3,9 @@ import pytest import pybind11_tests.odr_guard_1 as m -def test_sizeof_mrc_odr_guard(): - if hasattr(m, "sizeof_mrc_odr_guard"): - assert m.sizeof_mrc_odr_guard() == 4 - else: - pytest.skip("sizeof_mrc_odr_guard") - - def test_type_mrc_to_python(): - if hasattr(m, "type_mrc_to_python"): - assert m.type_mrc_to_python() == 1111 - else: - pytest.skip("type_mrc_to_python") + assert m.type_mrc_to_python() == 1111 def test_type_mrc_from_python(): - if hasattr(m, "type_mrc_from_python"): - assert m.type_mrc_from_python("ignored") == 111 - else: - pytest.skip("type_mrc_from_python") - - -def test_mrc_odr_guard(): - if hasattr(m, "mrc_odr_guard"): - i = m.mrc_odr_guard() - m.type_mrc_to_python() - j = m.mrc_odr_guard() - assert j == i + 1 - else: - pytest.skip("mrc_odr_guard") + assert m.type_mrc_from_python("ignored") == 111 diff --git a/tests/test_odr_guard_2.cpp b/tests/test_odr_guard_2.cpp index 820b7cc6c..3fedb08ce 100644 --- a/tests/test_odr_guard_2.cpp +++ b/tests/test_odr_guard_2.cpp @@ -1,22 +1,18 @@ #include "pybind11_tests.h" -#define USE_MRC_BBB -#ifdef USE_MRC_BBB namespace mrc_ns { // minimal real caster struct type_mrc { int value = -9999; }; -template struct minimal_real_caster { static constexpr auto name = py::detail::const_name(); - static std::int64_t odr_guard; // WANTED: ASAN detect_odr_violation + static constexpr std::uint64_t universally_unique_identifier = 2000; static py::handle cast(type_mrc const &src, py::return_value_policy /*policy*/, py::handle /*parent*/) { - odr_guard++; // Just to make sure it is used. - return py::int_(src.value + 2020).release(); // Actual ODR violation. + return py::int_(src.value + 2020).release(); // ODR violation. } // Maximizing simplicity. This will go terribly wrong for other arg types. @@ -26,7 +22,7 @@ struct minimal_real_caster { // NOLINTNEXTLINE(google-explicit-constructor) operator type_mrc const &() { static type_mrc obj; - obj.value = 22; // Actual ODR violation. + obj.value = 22; // ODR violation. return obj; } @@ -36,25 +32,16 @@ struct minimal_real_caster { } }; -template -std::int64_t minimal_real_caster::odr_guard = 0; - } // namespace mrc_ns namespace pybind11 { namespace detail { template <> -struct type_caster : mrc_ns::minimal_real_caster<> {}; +struct type_caster : mrc_ns::minimal_real_caster {}; } // namespace detail } // namespace pybind11 -#endif TEST_SUBMODULE(odr_guard_2, m) { -#ifdef USE_MRC_BBB - m.def("sizeof_mrc_odr_guard", - []() { return sizeof(mrc_ns::minimal_real_caster<>::odr_guard); }); m.def("type_mrc_to_python", []() { return mrc_ns::type_mrc{202}; }); m.def("type_mrc_from_python", [](const mrc_ns::type_mrc &obj) { return obj.value + 200; }); - m.def("mrc_odr_guard", []() { return mrc_ns::minimal_real_caster<>::odr_guard; }); -#endif } diff --git a/tests/test_odr_guard_2.py b/tests/test_odr_guard_2.py index 4784a48f8..21719ce19 100644 --- a/tests/test_odr_guard_2.py +++ b/tests/test_odr_guard_2.py @@ -3,32 +3,9 @@ import pytest import pybind11_tests.odr_guard_2 as m -def test_sizeof_mrc_odr_guard(): - if hasattr(m, "sizeof_mrc_odr_guard"): - assert m.sizeof_mrc_odr_guard() == 8 - else: - pytest.skip("sizeof_mrc_odr_guard") - - def test_type_mrc_to_python(): - if hasattr(m, "type_mrc_to_python"): - assert m.type_mrc_to_python() == 2222 - else: - pytest.skip("type_mrc_to_python") + assert m.type_mrc_to_python() == 2222 def test_type_mrc_from_python(): - if hasattr(m, "type_mrc_from_python"): - assert m.type_mrc_from_python("ignored") == 222 - else: - pytest.skip("type_mrc_from_python") - - -def test_mrc_odr_guard(): - if hasattr(m, "mrc_odr_guard"): - i = m.mrc_odr_guard() - m.type_mrc_to_python() - j = m.mrc_odr_guard() - assert j == i + 1 - else: - pytest.skip("mrc_odr_guard") + assert m.type_mrc_from_python("ignored") == 222