UBSan:存储到未对齐的地址;有什么问题,我应该关心吗

UBSan: Store to misaligned address; what is the problem, and should I care

我已经 运行 UBSan 下的一些代码,发现一个我以前从未见过的错误:

/usr/include/c++/7/bits/stl_algobase.h:324:8: runtime error: store to misaligned address 0x611000001383 for type 'struct complex', which requires 4 byte alignment
0x611000001383: note: pointer points here
 66  46 40 02 00 00 00 00 00  00 00 00 04 01 18 00 08  00 00 00 00 00 00 00 08  00 00 00 00 00 00 00
              ^

(g++-7.3.0, Ubuntu 18.04, flags -fsanitize=address -fsanitize=undefined)

这个错误是什么意思?它真的是一个错误吗(它在标准库中,所以它不会 坏,对吧?),我应该关心它吗?

您可能使用指针转换将一块原始内存转换为 complex*

示例:

void* raw = getBuffer(); // Made up function which returns a buffer
auto size = *static_cast<uint16_t>*(raw); // Maybe your format says that you got a 2 Byte size in front
auto* array = static_cast<complex*>(raw+sizeof(uint16_t)); // ... and complex numbers after
std::transform(array, array+size, ...);  // Pass this into STL

轰!你得到了 UB。

为什么?

The behavior is undefined in the following circumstances: [...]
Conversion between two pointer types produces a result that is incorrectly aligned

[...]

If the resulting pointer is not correctly aligned [68] for the referenced type, the behavior is undefined.

参见 (我从哪里得到这些)

这是什么意思?
每个指针都必须与其指向的类型对齐。对于 complex 这意味着对齐 4。简而言之,这意味着 array(从上面)必须被 4 整除(又名 array % 4 == 0)假设 raw 对齐到 4 个字节,您可以很容易地看到 array 不能像 (raw + 2) % 4 == 2(因为 raw % 4 == 2
如果 size 是一个 4 字节值,那么 array 将在(且仅当)raw 对齐时对齐。这是否有保证取决于它来自哪里。

所以是的,这确实是一个错误,可能会导致一个真正的错误,尽管并非总是如此(取决于月相等。因为它总是与 UB 一起使用,请参阅上面的答案了解详细信息)

不,它不在 STL 中,它恰好在那里被检测到,因为 UBSAN 监视内存取消引用。因此,虽然实际的 UB 是 static_cast<complex*>,但只有从该指针读取时才会检测到它。

您可以在执行程序之前使用 export UBSAN_OPTIONS=print_stacktrace=1 获取堆栈跟踪并找出错误转换的位置。

提示:您只需要检查转换。通过 new 分配的任何 struct/type 总是对齐的(以及内部的每个成员),除非使用像“打包结构”这样的技巧。