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

时间:2019-04-07 15:36:44

标签: ubsan

我已经在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 =地址-fsanitize =未定义)

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

1 个答案:

答案 0 :(得分:1)

您可能使用了指针转换,该转换将原始内存块转换为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监视内存取消引用,所以它恰好在STL中被检测到。因此,尽管实际的UB是static_cast<complex*>,但只有从该指针读取时才能检测到它。

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

提示:您只需要检查演员表。通过new分配的任何结构/类型总是对齐的(以及内部的每个成员),除非使用了诸如“压缩结构”之类的技巧。