- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我发现这段代码使用“-fsanitize=undefined,address”和不使用它会产生不同的结果。
int printf(const char *, ...);
union {
long a;
short b;
int c;
} d;
int *e = &d.c;
int f, g;
long *h = &d.a;
int main() {
for (; f <= 0; f++) {
*h = g;
*e = 6;
}
printf("%d\n", d.b);
}
命令行是:
$ clang -O0 -fsanitize=undefined,address a.c -o out0
$ clang -O1 -fsanitize=undefined,address a.c -o out1
$ clang -O1 a.c -o out11
$ ./out0
6
$ ./out1
6
$ ./out11
0
Clang 版本是:
$ clang -v
clang version 13.0.0 (/data/src/llvm-dev/llvm-project/clang 3eb2158f4fea90d56aeb200a5ca06f536c1df683)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /data/bin/llvm-dev/bin
Found candidate GCC installation: /opt/rh/devtoolset-7/root/usr/lib/gcc/x86_64-redhat-linux/7
Selected GCC installation: /opt/rh/devtoolset-7/root/usr/lib/gcc/x86_64-redhat-linux/7
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64
Found CUDA installation: /usr/local/cuda, version 10.2
操作系统和平台是:
CentOS Linux release 7.8.2003 (Core).0, x86_64 GNU/Linux
我的问题:
最佳答案
代码有问题吗?
出于实用目的,是的。
我认为这是与 Is it undefined behaviour to call a function with pointers to different elements of a union as arguments? 相同的潜在问题
正如 Eric Postpischil 指出的那样,从字面上看的 C 标准似乎允许您的代码,并要求它打印出 6(假设这与您的实现表示整数类型的方式以及它如何布置 union 的方式一致)。但是,这种字面意思会呈现 strict aliasing rule几乎完全无能为力,所以在我看来这不是标准作者的意图。
严格别名规则的精神是不能通过指向不同类型的指针访问同一个对象(字符类型等的某些异常(exception)),并且编译器可以基于这种情况永远不会发生的假设进行优化。虽然 d.a
和 d.c
严格来说并不是“同一对象”,它们确实具有重叠存储,我认为编译器作者将规则解释为也不允许通过指向不同类型的指针访问重叠对象。在这种解释下,您的代码将具有未定义的行为。
在 Defect Report 236委员会考虑了一个类似的例子,并指出它有未定义的行为,因为它使用了"具有不同类型但指定相同存储区域"的指针。然而,澄清这一点的措辞似乎从未出现在该标准的任何后续版本中。
无论如何,我认为实际的结果是你不能指望你的代码在现代编译器下“正确”工作,这些编译器强制执行对严格别名规则的解释。这是否是一个 clang 错误是一个意见问题,但即使您确实认为它是,那么它是一个他们可能永远不会修复的错误。
为什么会这样?
如果您使用 -fno-strict-aliasing
标志,然后你回到 6 行为。我的猜测是 sanitizer 碰巧抑制了其中的一些优化,这就是为什么在使用这些选项时您看不到 0 行为的原因。-O1
引擎盖下似乎发生了什么是编译器假定存储到 *h
和 *e
不交互(因为它们的类型不同),因此可以自由重新排序。于是吊起*h = g
在循环之外,因为毕竟多个存储到同一地址,没有中间负载,是多余的,只需要保留最后一个。正好把它放在循环后面,大概是因为不能证明e
不指向 g
,所以 g
的值循环后需要重新加载。所以d.b
的最终值源自 *h = g
这有效地做 d.a = 0
.
如何得到警告?
不幸的是,编译器不擅长在静态或运行时检查是否违反(他们对严格别名规则的解释)。我不知道有什么方法可以收到此类代码的警告。使用 clang,您可以使用 -Weverything
启用它支持的每个警告选项(其中许多是无用的或适得其反的),即使如此,它也不会给出有关您的程序的相关警告。
关于c - 为什么这段代码的结果有和没有 "-fsanitize=undefined,address"不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68963247/
我正在尝试使用 conda g++ 编译器使用 -fsanitize=undefined 编译程序。我遇到了“__ubsan_handle_type_mismatch”链接器错误。我在编译和链接中使用
我正在尝试编写一些代码来创建一个排序的链表,并仅插入唯一元素,以使链表保持排序。另外,我实现了一个函数来删除具有给定值的节点和一个打印它的节点。 我有一些必须运行的测试用例,测试软件需要 main.c
使用 -fsanitize 进行编译时,我是否必须使用它来编译每个目标? 我有一些不受它支持的目标(汇编和 C 目标)。 主要可执行文件是受支持的 C++ 文件。 fsanitize 有效吗?或者我需
编译像这样的cpp程序时 int main() { int a[5][5]; cout << a[5][5]; } 使用 -fsanitzie=address 编译时出现运行时异常,但是 in
我想在使用内存清理程序时清除 FD_ZERO 和 FD_SET 上的误报。清除它有点容易: #include ... __msan_unpoison(&readfds, sizeof(readfds
我正在开发一个大型 C++ 项目,用 clang 编译它会很痛苦,所以我坚持使用 GCC。 我想使用很好的 -fsanitize=leak 标志,我在之前的工作中已经与 clang 一起使用过该标志,
我发现这段代码使用“-fsanitize=undefined,address”和不使用它会产生不同的结果。 int printf(const char *, ...); union { long
我在这里有一个小的单元测试,它具有未定义的行为。 源代码: #include TEST(test, test) { int k = 0x7fffffff; k += 1; // ca
我正在使用gcc (SUSE Linux) 7.2.1 20171020编译以下C程序strcmp.c: #include #include int main () { char str1[
我遇到了一个错误无法始终重现,其中 free()在无效的堆指针上调用。对于有问题的代码,根本不可能将此问题减少到“最小”——(一旦我这样做了,它就解决了)。我无法发现任何明显的问题(例如从未调用 ca
当我使用 -fsanitize=address 编译我的 C++ 代码时,我的软件在退出时会打印出泄漏列表。有没有办法避免泄漏报告(我只对内存损坏感兴趣,而不是泄漏)?我用 ASAN flags pa
我正在尝试使用 -fsanitize=bounds 选项找出代码中的越界问题,但我遇到了奇怪的行为: 例如在下面的代码中: #include #include int main (int, cha
将 -fsanitize=address -fno-omit-frame-pointer 与 clang 一起使用时需要注意什么?我经历了一些奇怪的事情debugging behaviour (std
我有一个用 g++ 正常编译的 MEX 文件。 我最近将其编译更改为使用 clang++,并将 -fsanitize=address 包含到 LDFLAGS 和 CFLAGS 中(注意:没有 CXX该
我正在尝试使用 asan 调试 clang 检测到的内存错误,但 valgrind 错过了。但是我无法让我的 clang 构建二进制文件来给我任何有用的调试信息。我可以用一个简短的测试程序来证明这一点
更新(2016 年 9 月 30 日) gcc-6.2 的 Ubuntu 版本((Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901)不再有这个问题。 我正在使用
我想知道 gcc 的 -fsanitize=address 选项与 tcmalloc 一起使用吗?还是我们需要通过禁用 tcmalloc 来运行?或者如果启用 tcmalloc 运行 sanitize
在下面的代码中我遇到了问题。当我给它一个仍然完全为空的 vector 时,代码崩溃,因为 vector.size() - 1 不能为负,因此它环绕。因为 vector 是空的,所以访问 contain
char t = 'a'; char * p1 = &t; char** p2 = &p1; std::cout << p2 << " " << *p2 << " " << **p2 << '\n';
我一直在尝试利用一些 GCC Instrumentation Options用于运行时检查以尝试调试/诊断我在 C++ 代码的特定区域中遇到的问题。 为了尝试缩小问题范围,我开始启用其中一些功能,但在
我是一名优秀的程序员,十分优秀!