我是否应该担心“条件跳转或移动取决于未初始化的值”?

时间:2009-04-19 19:10:23

标签: c++ valgrind memcheck

如果您使用过Memcheck(来自Valgrind),您可能会熟悉此消息......

  

条件跳转或移动取决于未初始化的值

我已经读过这个,当你使用未初始化的值时就会发生这种情况。

MyClass s;
s.DoStuff();

这样可以正常工作,因为s会自动初始化...所以如果是这样的话,那么,为什么Memcheck告诉我它没有初始化?消息应该被忽略吗?

也许我误解了错误指示我的位置。从Valgrind手册中,实际错误的片段是......

int main()
{
  int x;
  printf ("x = %d\n", x);
}

然而,在我的代码中,我看不到类似的东西。我注意到,堆栈顶部的函数跟踪Memcheck显示我是一个虚函数;这可能与它有关吗?

==14446== Conditional jump or move depends on uninitialised value(s)
==14446==    at 0x414164: vimrid::glut::GlutApplication::FinishRender() (GlutApplication.cpp:120)
==14446==    by 0x422434: vimrid::demos::filterdemos::FilterDemo3::Render() (FilterDemo3.cpp:260)
==14446==    by 0x412D3D: vimrid::VimridApplication::UpdateAndRender() (VimridApplication.cpp:93)
==14446==    by 0x4144BA: vimrid::glut::GlutApplication::glutHandleDisplay() (GlutApplication.cpp:201)
==14446==    by 0x41486A: vimrid::glut::GlutApplication::glutCallbackDisplay() (GlutApplication.cpp:277)
==14446==    by 0x54D9FAA: (within /usr/lib64/libglut.so.3.8.0)
==14446==    by 0x54DDA4A: fgEnumWindows (in /usr/lib64/libglut.so.3.8.0)
==14446==    by 0x54DA4A3: glutMainLoopEvent (in /usr/lib64/libglut.so.3.8.0)
==14446==    by 0x54DAEB5: glutMainLoop (in /usr/lib64/libglut.so.3.8.0)
==14446==    by 0x413FF8: vimrid::glut::GlutApplication::Run() (GlutApplication.cpp:112)
==14446==    by 0x41249D: vimrid::Launcher::runDemo(vimrid::VimridSettings&) (Launcher.cpp:150)
==14446==    by 0x412767: vimrid::Launcher::Launch(int, char**) (Launcher.cpp:62)

更新1:

我看了一下GlutApplication.cpp:120,看起来未初始化的变量被传递到该行的函数中。简单!

6 个答案:

答案 0 :(得分:17)

您可以将标志--track-origins=yes添加到valgrind,它将为您提供有关未初始化数据来源的信息。它运行速度较慢,但​​可能会有所帮助。

来源:Valgrind User Manual

答案 1 :(得分:6)

您可以发布更完整的样本吗?很难看出在某种形式的goto或flow changing语句中会出现特定错误。

我最常在代码中看到此错误,如下所示

MyClass s1;
...
if ( someCondition ) { 
  goto Foo:
}
MyClass s2;
Foo:
cout << s2.GetName();

此代码根本不正确。原因是即使s2有一个构造函数,如果someCondition为true,它也不会被执行。 goto语句将跳过初始化,并且在程序的最后一行s2将是未初始化的并且基本上指向垃圾。

修改

您可能还想查看此页面,其中提供了有关如何解读此特定valgrind错误的提示

https://computing.llnl.gov/code/memcheck/#deciphering4

<强>附录

我刚刚发现的另一个常见原因是当你将一些整数常量传递给一个可变函数时,它们作为整数放在堆栈上,但是当被调用者得到它时,你就遇到了问题在64位计算机上。

我几乎要放弃了,只考虑valgrind是愚蠢的,然后我意识到只需将它转换为长期修复它。

所以我的结论是:认真对待这些消息。

答案 2 :(得分:3)

如果Valgrind声明某个值未初始化,那么在99.5%中它实际上没有初始化。通常,当编译器报告使用未初始化的值(-Guninitialized在GCC中)时,检查内联展开,因为您的未初始化值可以声明(而不是初始化),例如10级内联函数“调用”(或模板展开)比GCC实际报告更高。 Valgrind做同样的事,但在运行时。因此,您应该检查从未声明(未初始化)位置到未实际值的整个路径到实际使用的位置。该路径可以是例如:函数调用的级联,其中每个函数将其参数(以及可能未初始化的值)传递给下一个函数。 当实际使用该值时,Valgrind将报告最后一个函数。

一般来说,你不应该忽视Valgrind所说的。 Valgrind不是一个简单的跟踪程序。 可以将其视为虚拟机:

  

Valgrind本质上是虚拟的   使用即时(JIT)的机器   编译技术,包括   动态重新编译。没什么   原始程序运行   直接在主处理器上。   相反,Valgrind首先翻译了   程序成一个临时的,简单的形式   称为中间代表   (IR),处理器中立,   基于SSA的表格。转换后,   一个工具(见下文)是免费的   它想要的任何转变   在Valgrind翻译之前,在IR上   IR回到机器代码并让   主处理器运行它。即使   它可以使用动态翻译(即   是,主机和目标处理器   它来自不同的架构)   没有。 Valgrind重新编译二进制文件   代码在主机和目标上运行(或   模拟)相同的CPU   建筑。 (维基百科)

答案 3 :(得分:1)

如果您可以发布更多代码,尤其是来自valgrind认为错误的部分,那将非常有用。

如果每次实例化该类时都会发生这种情况,您可能忘记初始化构造函数中的一个成员。

是的:你应该担心这个错误,那些家伙真的可以咬你。

答案 4 :(得分:1)

在64位机器中。 通常,int在内存中占用4个字节。但是很长一段时间内存需要8个字节。因此,只需引用一个int值,因为长格式将导致完全错误的结果。 在这种情况下需要转换。

答案 5 :(得分:-1)

错误似乎不是来自您的代码,而是来自您正在使用的库。

Valgrind带有一些默认的错误抑制,但这可能不包括你正在使用的库。

  

错误检查工具可以检测基础库中的许多问题,例如GNU C库和X11客户端库,这些库预装在GNU / Linux系统上。您无法轻松修复这些错误,但您不希望看到这些错误(是的,有很多错误!)因此,Valgrind会在启动时读取要抑制的错误列表。构建系统时,。/ configure脚本会创建默认抑制文件。

您可以创建自己的error suppressions,而这些Why does Valgrind not like my usage of glutCreateWindow?与您的代码无关。

查看类似的SO问题{{3}}