为什么 Valgrind 不检测未初始化变量的使用?

emp*_*rai 1 c++ debugging valgrind

据我了解,当代码包含未初始化变量的使用时,Valgrind 应该报告错误。在下面的玩具示例中,printer未初始化,但程序“愉快”地打印了消息。

#include <iostream>

class Printer {
    public:
        void print() {
            std::cout<<"I PRINT"<<std::endl;
        }
};


int main() {
    Printer* printer;
    printer->print();
};
Run Code Online (Sandbox Code Playgroud)

当我用 Valgrind 测试这个程序时,它没有报告任何错误。

这是预期的行为吗?如果是的话,为什么会这样?

Fra*_*rax 5

该变量实际上从未被使用过。

  1. 该方法调用是内联的1,因此该变量不会作为参数传递。
  2. 该方法本身不this以任何方式使用,因此根本不使用该变量。

以上与打开或关闭优化无关。

事实上,在优化的代码中,变量根本不会存在——即使作为内存分配也是如此。

关于类似情况的问题:仅在标头中的外部变量意外工作,为什么?


1类体中定义的所有方法默认都是内联的。

这是未定义的行为吗?

是的。调用该方法需要this指向一个实际的、初始化的对象实例,以便格式良好。正如 Nir ​​Friedman 指出的那样,编译器可以自由地假设并在此基础上进行优化(IIRC 这种优化甚至可以发生-O0!)。

我个人希望所讨论的特定代码能够在任何实际条件下工作(因为指针值实际上无关紧要),但我永远不会依赖于此。您应该立即修复您的代码。

检测

要检测 Clang/GCC 中未初始化变量的使用情况,请使用 option -Wuninitialized(或简单地使用-Wall,其中包含此标志)。

-Wuninitialized应该主要涵盖堆栈分配内存的使用,尽管我猜想堆栈分配数组的某些使用可能仍然会失败。某些编译器可能支持使用-fsanitize=...选项对未初始化读取进行额外的运行时检查,例如-fsanitize=memoryClang (thx, chtz )。这些检查应涵盖边缘情况以及堆分配内存的使用。