优化如何触发Valgrind误报?

3

引用Valgrind教程:

优化的代码可能会导致valgrind错误地报告未初始化值错误。作者知道如何修复此问题,但这会使valgrind变得非常缓慢(而且它已经相当缓慢了)。建议的解决方法是在使用valgrind调试代码时不进行优化。无论如何,在调试时不进行优化是一个好的经验法则。

(来源: https://people.gnome.org/~newren/tutorials/developing-with-gnome/html/ch03s03.html

什么类型的优化会导致这种情况,并且它们并不是真正的问题?


“它们怎么不是真正的问题呢?” Valgrind 用于查找源代码中的问题。它通过查看目标代码来实现这一点,但如果问题在源代码中不存在,只是从目标代码中看起来可能存在,那么这就是一个虚假阳性,没有什么需要修复的。 - Pascal Cuoq
我的意思是,我希望优化不会破坏任何东西...所以警告并不表示真正的问题。它们是编译器知道不会影响程序输出的未初始化数据的真实用途,还是Valgrind跟踪方式的产物? - user1476176
需要记住的一件事是汇编比C语言“更加明确定义”。即使它们看起来像是不明确的C指令的直接翻译,汇编指令也可以具有明确定义的含义。为了说明这一点(尽管我认为这个例子太简单了,不能说明Valgrind手册所说的内容),考虑将xor reg,reg指令作为函数的第一条指令,其中reg是一个调用者保存寄存器。这个汇编指令总是合法的。它可以是int x; x ^= x;(非法的C代码)的未优化翻译。或者它可以是int x=0;的优化翻译。 - Pascal Cuoq
Valgrind可能会警告xor reg,reg,认为它对应于int x; x ^ = x;,但如果程序是使用优化编译的,则此指令实际上对应于安全的源级构造int x = 0;。(重申一遍,我不认为这是一个真实的例子,但一个真实的例子可能看起来像这个。) - Pascal Cuoq
1个回答

6
什么类型的优化会导致这种问题,它们为什么不是真正的问题?
一个特定的例子是:glibc有一个strlen()函数
- 确定一个指针是否为4字节对齐 - 一次读取4个字节,然后使用位操作技巧来确定这4个字节中是否有任何一个字节是0。
这是“安全”的,因为它永远不会导致崩溃(从4字节对齐的指针读取4个字节永远不会越过页面边界),但它可能会在分配的块的末尾之外“过度读取”(例如,如果字符串来自strdup("hello") -- 这里只分配了6个字节,但strlen将读取8个字节)。
现在,这个特定的实例对Valgrind没有问题,因为它将strlen重定向到自己的副本中。
但是,在你自己的代码中进行类似的循环展开时,可能会发生类似的情况,并且Valgrind会报告一个错误的结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接