boost :: serialization中的派生类偏移量计算。有效吗?

问题描述 投票:2回答:2

[boost::serialization包含this code

reinterpret_cast<std::ptrdiff_t>(
    static_cast<Derived *>(
        reinterpret_cast<Base *>(1 << 20)
    )
) - (1 << 20)

其目的是计算基类和派生类之间的偏移量。此代码是否包含未定义的行为?


我问的原因是ASAN + UBSAN抱怨。例如,此代码

#include <iostream>

class Foo { public: virtual void foo() {} };
class Base { public: virtual void base() {} };
class Derived: public Foo, public Base {};

int main()
{
    std::cout <<
       (reinterpret_cast<std::ptrdiff_t>(
            static_cast<Derived *>(
                reinterpret_cast<Base *>(1 << 20)
            )
       ) - (1 << 20));
}

编译为(gcc版本9.2.1)

g++ -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -g main.cpp

产生此输出

AddressSanitizer:DEADLYSIGNAL
=================================================================
==72613==ERROR: AddressSanitizer: SEGV on unknown address 0x0000000ffff8 (pc 0x0000004012d9 bp 0x7ffd5b3eecf0 sp 0x7ffd5b3eece0 T0)
==72613==The signal is caused by a READ memory access.
    #0 0x4012d8 in main main.cpp:13
    #1 0x7f74a90d5f42 in __libc_start_main (/lib64/libc.so.6+0x23f42)
    #2 0x40112d in _start (/home/.../a.out+0x40112d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV main.cpp:13 in main

这是假阳性还是此代码确实有问题?

c++ boost boost-serialization
2个回答
1
投票
reinterpret_cast<Base *>(1 << 20)

这不是有效的指针。

[static_cast ing它需要评估它,它具有不确定的行为。

这是一个有趣的“技巧”,但似乎定义不明确,-fsanitize选项的结果证实了这一点。

This does not seem to be unusual for boost::serialization


0
投票

如另一个答案所示,问题在于boost::serialization不是任何对象的地址。使用原则上可以存储(1 << 20)char[]似乎可以解决此问题:

Derived

这是假阳性还是此代码确实有问题?

根据对标准的严格阅读,该代码确实具有UB,因此从某种意义上说,它不是false肯定的。实际上,boost作者和编译器作者都同意这只是指​​针数学,因此无论如何它应该做正确的事情。

编辑:除非涉及的碱基之一是#include <stdint.h> #include <stddef.h> #include <stdio.h> class Foo { public: virtual void foo() {} }; class Base { public: virtual void base() {} }; class Derived: public Foo, public Base {}; int main() { alignas (Derived) char const buffer[sizeof(Derived)] = {}; Derived const* const derived = reinterpret_cast<Derived const*>(buffer); Base const* const base = derived; ptrdiff_t const delta = reinterpret_cast<char const*>(derived) - reinterpret_cast<char const*>(base); ::printf("%td\n", delta); return 0; } 。然后强制转换将尝试从vtable读取偏移量。

编辑2:使用virtual会产生0。已更改为使用本地对齐的缓冲区。

© www.soinside.com 2019 - 2024. All rights reserved.