0

我一直在 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,标志 -fsanitize=address -fsanitize=undefined)

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

4

1 回答 1

3

您可能使用了一个指针转换,它将一块原始内存转换为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。

为什么?

在以下情况下行为未定义:[...]
两种指针类型之间的转换会产生错误对齐的结果

[...]

如果结果指针未正确对齐 [68] 引用类型,则行为未定义。

请参阅https://stackoverflow.com/a/46790815/1930508(我从哪里得到这些)

这是什么意思?
每个指针都必须与其指向的类型对齐。因为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始终对齐(以及内部的每个成员),除非使用诸如“打包结构”之类的技巧。

于 2019-08-02T06:53:58.200 回答