引用 Valgrind 教程:
优化的代码可能会导致 valgrind 错误地报告未初始化值错误。作者知道如何解决这个问题,但这会使 valgrind 变慢(而且它已经相当慢了)。建议的修复方法是在尝试使用 valgrind 调试代码时不进行优化。无论如何,调试时不优化是一个很好的经验法则。
(来源:https://people.gnome.org/~newren/tutorials/developing-with-gnome/html/ch03s03.html)
什么类型的优化会导致这种情况,它们为什么不是真正的问题?
什么类型的优化会导致这种情况,它们为什么不是真正的问题?
一个具体实例:glibc 有
strlen()
这是“安全的”,因为它永远不会导致崩溃(从 4 字节对齐指针读取 4 个字节永远不会跨越页边界),但它可能会“过度读取”超过已分配块的末尾(例如如果字符串来自
strdup("hello")
- 这里只分配了 6 个字节,但 strlen
将读取 8)。
现在,这个特定实例对于 Valgrind 来说不是问题,因为它将
strlen
重定向到它自己的副本。
但是类似的循环展开可能会发生在您自己的优化代码中,然后 Valgrind 会报告误报。
请参阅我在 Reddit 上写的这篇文章:
我只知道一种情况,优化会导致彻头彻尾的误报。
这是两个链接 std::g++ 可选 和 std::可选的 clang++
问题代码如下
if (f && *f != a)
其中
f
是 std::optional
。编译器知道 std::optional
位于堆栈上,因此内存是可寻址的。编译器(clang++ 和 g++)通过交换 &&
操作数的顺序来优化这一点。 *f
可能未初始化,但它是可寻址的。当未初始化时,f
为 false。
Valgrind 尝试恢复原始
if
的语义,但如果原始 RHS 是指针,它(还)无法做到这一点。结果是误报“条件跳转或移动取决于未初始化的值”错误。