我试图理解我们最近在使用 Clang 5.0 和 Undefined Behavior Sanitizer (UBsan) 时清除的问题。我们有代码可以向前或向后处理缓冲区。简化的情况类似于下面显示的代码。
0-len
可能看起来有点不寻常,但早期的 Microsoft .Net 编译器需要它。Clang 5.0 和 UBsan产生整数溢出结果:
adv-simd.h:1138:26: runtime error: addition of unsigned offset to 0x000003f78cf0 overflowed to 0x000003f78ce0
adv-simd.h:1140:26: runtime error: addition of unsigned offset to 0x000003f78ce0 overflowed to 0x000003f78cd0
adv-simd.h:1142:26: runtime error: addition of unsigned offset to 0x000003f78cd0 overflowed to 0x000003f78cc0
...
第 1138、1140、1142 行(和朋友)是增量,由于0-len
.
ptr += inc;
根据C 中的指针比较。它们是有符号的还是无符号的?(其中还讨论了 C++),指针既不是有符号的也不是无符号的。我们的偏移量是无符号的,我们依靠无符号整数换行来实现反向跨步。
该代码在 GCC UBsan 和 Clang 4 以及更早的 UBsan 下运行良好。在 LLVM 开发人员的帮助下,我们最终为 Clang 5.0 清除了它。而不是size_t
我们需要使用ptrdiff_t
.
我的问题是,构造中的整数溢出/未定义行为在哪里?如何ptr + <unsigned>
导致有符号整数溢出并导致未定义的行为?
这是一个反映真实代码的 MSVC。
#include <cstddef>
#include <cstdint>
using namespace std;
uint8_t buffer[64];
int main(int argc, char* argv[])
{
uint8_t * ptr = buffer;
size_t len = sizeof(buffer);
size_t inc = 16;
// This sets up processing the buffer in reverse.
// A flag controls it in the real code.
if (argc%2 == 1)
{
ptr += len - inc;
inc = 0-inc;
}
while (len > 16)
{
// process blocks
ptr += inc;
len -= 16;
}
return 0;
}