C++ 运行时错误(使用 -fsanitize=undefined):对象有一个可能无效的 vptr:abs(偏移到顶部)太大

C++ runtime error (using -fsanitize=undefined): object has a possibly invalid vptr: abs(offset to top) too big

我的代码:

const int N = 1048569;
struct A { };
struct B : virtual public A {
    char space[N];
};
struct C : virtual public A {
    void foo() {};
};
struct D : public B, public C { };

D T;
int main() {
    T.foo();
    return 0;
}

当我用 -fsanitize=undefined 编译我的代码时,我得到以下 运行 时间错误:

a.cpp:13:10: runtime error: member call on address 0x560aead1e6a8 which does not point to an object of type 'C'
0x560aead1e6a8: note: object has a possibly invalid vptr: abs(offset to top) too big
 00 00 00 00  b0 dc c1 ea 0a 56 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00
              ^~~~~~~~~~~~~~~~~~~~~~~
              possibly invalid vptr

如果我不使用 -fsanitize=undefined 选项,程序 运行 成功。

此外,如果我将 N 的值设置为 1048568(仅减 1),程序 运行s 在这两种情况下都会成功。

不知道是我的错还是只是因为fsanitize无法处理这么大的尺寸

这是由 Clang 的 UndefinedBehaviour Sanitizer 设置的任意大小限制:

https://github.com/llvm/llvm-project/blob/5745eccef54ddd3caca278d1d292a88b2281528b/compiler-rt/lib/ubsan/ubsan_type_hash.h#L55-L57

/// A sanity check for Vtable. Offsets to top must be reasonably small
/// numbers (by absolute value). It's a weak check for Vtable corruption.
const int VptrMaxOffsetToTop = 1<<20;
Itanium ABI 中的

"offset-to-top" 是 vtable 中每个对象(和基础 class 子对象)的 ptrdiff_t 值,当添加到指针时,会给出一个指向最派生对象的指针(您 new 或声明为变量的类型)。这就是 dynamic_cast<void*>(pointer_to_base) 使用的内容。 UBSan 预计这会相对较小,因为您的 classes 无论如何都不会那么大和偏移。这意味着它会这么大的唯一情况是你不小心溢出缓冲区并直接写入 vtable。

如果你真的需要这样做,“修复”这个问题的方法是将大 class 作为你的第二个基地 class,因此它的偏移量会相对较小。