c++ - 使用 boost 序列化时解决 sanitizer 错误

标签 c++ serialization boost address-sanitizer ubsan

我最近尝试使用 boost 序列化来序列化一个包含 std::vector<std::unique_ptr<Base>>> 的类。作为成员(member)。根据 boost 文档( https://www.boost.org/doc/libs/1_71_0/libs/serialization/doc/serialization.html#derivedpointers ),我们必须使用方法 register_type 注册派生类序列化的存档文件才能正常工作。一切确实构建并运行良好,但地址 sanitizer 构建(在我们的 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)

从代码和注释来看,这个表达式是在计算Base的位移类(class)内Derived .但是,它看起来仍然很神奇,尤其是将(看似)随机数转换为 Base 时。指针。如果有人能够解释为什么这实际上计算了位移,那就太好了。

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

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

最佳答案

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

这是编译器中的一个错误,所以我强烈建议将此报告给 sanitizer 开发人员:

  • GCC Bugzilla
  • (如果问题通过 Clang 重现)在 Github tracker
  • 关于c++ - 使用 boost 序列化时解决 sanitizer 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59210778/

    相关文章:

    c++ - 通过静态函数增加非静态变量

    c++ - 在另一个结构中释放一个结构内的指针

    java - 如何在Java中序列化不可序列化的对象?

    Java自动字段值序列化

    c++ - 如何重载operator<<以与boost::program_options默认值输出一起使用?

    c++ - 使用 png++ 编写 png 图像

    C++浮点问题

    java - JSF 2 - @ViewScoped bean 在请求之间存在于何处?

    c++ - 用于解析 C++ 中重复日期描述的库?

    c++ - 我应该编写什么代码才能深入了解高级 C++?