您可能使用了一个指针转换,它将一块原始内存转换为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
始终对齐(以及内部的每个成员),除非使用诸如“打包结构”之类的技巧。