使用Boost序列化时解决消毒剂错误

我最近尝试使用boost序列化来序列化一个包含std::vector<std::unique_ptr<Base>>>作为成员的类。根据boost文档(https://www.boost.org/doc/libs/1_71_0/libs/serialization/doc/serialization.html#derivedpointers),我们必须使用存档的方法register_type注册派生类,才能使序列化正常工作。一切确实可以构建并运行良好,但地址清理器构建(在我们的CI中运行)失败,并出现以下错误:

ASAN:DEADLYSIGNAL
=================================================================
==3==ERROR: AddressSanitizer: SEGV on unknown address 0x000000100000 (pc 0x559bc5f18288 bp 0x7ffe74fd8d30 sp 0x7ffe74fd8d10 T0)
==3==The signal is caused by a READ memory access.
==3==Hint: address points to the zero page.
    #0 0x559bc5f18287 in boost::serialization::void_cast_detail::void_caster_primitive<Derived,Base>::void_caster_primitive() /usr/include/boost/serialization/void_cast.hpp:188
    #1 0x559bc5f1714a in boost::serialization::singleton<boost::serialization::void_cast_detail::void_caster_primitive<Derived,Base> >::get_instance()::singleton_wrapper::singleton_wrapper() /usr/include/boost/serialization/singleton.hpp:117
    #2 0x559bc5f173be in boost::serialization::singleton<boost::serialization::void_cast_detail::void_caster_primitive<Derived,Base> >::get_instance() /usr/include/boost/serialization/singleton.hpp:118
    #3 0x559bc5ef3294 in __static_initialization_and_destruction_0 /usr/include/boost/serialization/singleton.hpp:155
    ...

检查void_cast.hpp中的内容后,我发现了void_caster_primitive的构造函数中有问题的代码:

/* note about displacement:
 * displace 0: at least one compiler treated 0 by not shifting it at all
 * displace by small value (8): caused ICE on certain mingw gcc versions */
reinterpret_cast<std::ptrdiff_t>(
    static_cast<Derived *>(
        reinterpret_cast<Base *>(1 << 20)
    )
) - (1 << 20)

根据代码和注释,此表达式正在计算BaseDerived类的位移。但是,它仍然看起来像魔术,尤其是将(看似)随机数强制转换为Base指针时。如果有人能阐明为什么它实际上计算出位移,那将是很好的。

编辑: 这是一个使用上面显示的位移计算方法的简单示例:https://godbolt.org/z/Bmp7zH如果关闭了消毒剂,它将编译并运行,但是在打开消毒剂后,程序会异常终止。

这也是尝试在编译器资源管理器上重现SEGV的原始问题:https://godbolt.org/z/w8ZNx8但是,链接boost序列化似乎不起作用,而且如果我打开sanitizer选项,有时构建也会发生

kentkent33 回答:使用Boost序列化时解决消毒剂错误

此问题实际上不是由Asan引起的,而是由 UB san引起的,后者在转换期间执行类类型验证(通过读取和分析对象的vptr)。尝试用假地址读取内存会导致您的情况崩溃。

这是编译器中的错误,因此我强烈建议将此报告给消毒剂开发人员:

本文链接:https://www.f2er.com/2963871.html

大家都在问