【问题标题】:Is this write to an array truly undefined behavior in C? [duplicate]这是在 C 中写入数组真正未定义的行为吗? [复制]
【发布时间】:2021-12-25 05:52:35
【问题描述】:

如果一个数组超出另一个数组的末尾,则此代码通过指针写入一个值。

#include <stdio.h>
#include <inttypes.h>

extern int first[], second[];

#define ADDR_AFTER(ptr) ((uintptr_t)((ptr) + 1))

int test(int *an_int) {
    *second = 1;
    if (ADDR_AFTER(first) == (uintptr_t)an_int) {
        // ubsan does not like this.
        *an_int = 2;
    }
    return *second;
}

int first[1] = {0}, second[1] = {0};

int main() {
    if (ADDR_AFTER(first) == (uintptr_t)second) {
        printf("test: %d\n", test(second));
        printf("x: %d y: %d\n", *first, *second);
    }
}

我绝不会直接比较指向不同对象的两个指针(因为我首先将它们转换为uintptr_t)。我创建了一个指向数组末尾的指针(这是合法的),但我从不取消引用该指针。据我所知,这应该不打印,或者打印:

测试:2 x: 0 y: 2

当优化为-O1 或更低时,会在 Clang 上打印。但是,在-O2,它会打印:

测试:1 x: 0 y: 2

使用-O2 -fsanitize=undefined,它将 this 打印到标准输出:

测试:2 x: 0 y: 2

以及以下到标准错误:

运行时错误:存储到地址 0x000000cd9efc 没有足够的空间用于“int”类型的对象 0x000000cd9efc:注意:指针指向这里 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

引用test 中对an_int 的赋值。这实际上是未定义的行为,还是 Clang 中的错误?

【问题讨论】:

  • 严格别名在这里不适用,因为p 是一个指向int 的指针,它没有被标记为restrict。因此,明确允许使用别名 y
  • 重命名我提到的一个变量确实更好,但是..您是想让人们更容易回答它还是想掩盖问题?请做一个更好的。给所有变量正确的名字。
  • 不完全是重复但密切相关:stackoverflow.com/questions/45966762/…
  • 使用n4713草案,标准的相关部分是第8.5.10节第(2.1)段:“如果一个指针代表一个完整对象的地址,另一个指针代表最后一个地址不同完整对象的元素,88 比较的结果是未指定的。”但请注意,“未指定”与“未定义”不同。
  • 这是一个已知的编译器错误。有一个关于它的现有问题;我会寻找它。编译器错误地“推断”当执行在比较两个指针的if (a == b) 的“then”子句内时,ab 必须指向同一“数组”中的元素(使用定义== 运算符的“数组”,它将单个对象视为一个元素的数组。

标签: c pointers gcc clang undefined-behavior


【解决方案1】:

您的代码没有任何无效,编译器错误。如果您在 test() 中删除不必要的 ADDR_AFTER 检查,代码将按预期运行,不会出现 UBSan 错误。如果您在启用优化且未使用 UBSan 的情况下运行它,则会得到错误的输出(test=1,应该是 2)。

test() 中的 ADDR_AFTER(first) == (uintptr_t)an_int 代码导致 Clang 在使用 -O2 编译时会出错。

我使用Apple clang version 11.0.3 (clang-1103.0.32.62) 进行了测试,但看起来 Clang 13 和当前主干也有错误:https://godbolt.org/z/s83ncTsbf - 如果您将编译器更改为任何版本的 GCC,您会看到它可以从 @987654327 返回 1 或 2 @,而 Clang 总是返回 1 (mov eax, 1)。

您可能应该为此提交一个 Clang 错误。

【讨论】:

    猜你喜欢
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 2022-12-22
    相关资源
    最近更新 更多