我试图不理解我们最近在使用Clang 5.0和Undefined Behavior Sanitizer(UBsan)时解决的问题。我们有处理向前或向后缓冲区的代码。减少的大小写为similar to the code shown below
0-len看起来可能有点不寻常,但是早期的Microsoft .Net编译器需要它。 Clang 5.0和UBsan produced integer overflow findings:

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(和 friend )是增量,可能会
由于0-len向后移动。
ptr += inc;

根据Pointer comparisons in C. Are they signed or unsigned?(还将讨论C++),指针既不带符号也不带符号。我们的偏移量是无符号的,我们依靠无符号整数换行来实现反向跨度。

在GCC UBsan和Clang 4和更早的UBsan下,该代码很好用。我们最终使用help with the LLVM devs在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;
}

最佳答案

向指针添加整数的定义是(N4659 expr.add / 4):

c&#43;&#43; - 指针加法和Clang 5.0和UBsan的整数溢出?-LMLPHP

我在这里使用了图像以保留格式(这将在下面讨论)。

注意,这是一个新的措词,代替了先前标准中不太清晰的描述。

在您的代码中(当argc为奇数时),我们最终得到的代码等效于:

uint8_t buffer[64];
uint8_t *ptr = buffer + 48;
ptr = ptr + (SIZE_MAX - 15);

对于应用于您的代码的标准报价中的变量,i48j(SIZE_MAX - 15)n64

现在的问题是0≤i + j≤n是否成立。如果我们将“i + j”解释为表示i + j的结果,则等于32,小于n。但是,如果这意味着数学结果,则它比n大得多。

该标准在此处将字体用于数学方程式,而不在源代码中使用该字体。 也不是有效的运算符。所以我认为他们打算用这个方程式来描述数学值,即这是不确定的行为。

09-08 10:35