#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 <typename Ignored = void> struct minimal_real_caster { static constexpr auto name = py::detail::const_name<type_mrc>(); static std::int64_t odr_guard; // WANTED: ASAN detect_odr_violation 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. } // Maximizing simplicity. This will go terribly wrong for other arg types. template <typename> using cast_op_type = const type_mrc &; // NOLINTNEXTLINE(google-explicit-constructor) operator type_mrc const &() { static type_mrc obj; obj.value = 22; // Actual ODR violation. return obj; } bool load(py::handle src, bool /*convert*/) { // Only accepts str, but the value is ignored. return py::isinstance<py::str>(src); } }; template <typename Ignored> std::int64_t minimal_real_caster<Ignored>::odr_guard = 0; } // namespace mrc_ns namespace pybind11 { namespace detail { template <> struct type_caster<mrc_ns::type_mrc> : 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 }