C++ 我是否应该担心“条件跳转或移动取决于未初始化的值”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/765913/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Should I worry about "Conditional jump or move depends on uninitialised value(s)"?
提问by Nick Bolton
If you've used Memcheck (from Valgrind) you'll probably be familiar with this message...
如果您使用过 Memcheck(来自 Valgrind),您可能会熟悉此消息......
Conditional jump or move depends on uninitialized value(s)
条件跳转或移动取决于未初始化的值
I've read about this and it simply occurs when you use an uninitialized value.
我已经读过这个,它只是在您使用未初始化的值时发生。
MyClass s;
s.DoStuff();
MyClass s;
s.DoStuff();
This will work because s
is automatically initialized... So if this is the case, and it works, why does Memcheck tell me that it's uninitialized? Should the message be ignored?
这会起作用,因为它s
是自动初始化的......所以如果是这种情况,并且它起作用,为什么 Memcheck 告诉我它未初始化?是否应该忽略该消息?
Perhaps I misunderstood where the error was directing me. From the Valgrind manual, the actual erroneous snippet is...
也许我误解了错误指向我的方向。从 Valgrind 手册中,实际的错误片段是......
int main()
{
int x;
printf ("x = %d\n", x);
}
However, in my code, I can't see anything like that. I have noticed however that the function at the top of the stack trace Memcheck shows me is a virtual function; could this be something to do with it?
但是,在我的代码中,我看不到这样的东西。然而,我注意到堆栈跟踪 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)
Update 1:
更新 1:
I took a look at GlutApplication.cpp:120, and it looks like the uninitialized variable was being passed in to a function on that line. Simple!
我查看了 GlutApplication.cpp:120,看起来未初始化的变量正在被传递给该行上的一个函数。简单的!
回答by rocarvaj
You can add the flag --track-origins=yes
to valgrind and it will give you information on the sources of uninitialised data. It runs slower, but can be helpful.
您可以将标志添加--track-origins=yes
到 valgrind,它将为您提供有关未初始化数据来源的信息。它运行速度较慢,但可能会有所帮助。
Source: Valgrind User Manual
回答by JaredPar
Can you post a more complete sample? It's hard to see how there would be that particular error with out some form of goto or flow changing statement.
你能发布一个更完整的样本吗?如果没有某种形式的 goto 或 flow 更改语句,很难看出会出现该特定错误。
I most commonly see this error in code like the following
我最常在如下代码中看到此错误
MyClass s1;
...
if ( someCondition ) {
goto Foo:
}
MyClass s2;
Foo:
cout << s2.GetName();
This code is fundamentally incorrect. The reason why is that even though s2 has a constructor, it's not executed if someCondition is true. The goto statement will jump over the initialization and at the last line of the program s2 will be uninitialized and essentially point to garbage.
这段代码从根本上是不正确的。原因是即使 s2 有一个构造函数,如果 someCondition 为真,它也不会执行。goto 语句将跳过初始化,在程序的最后一行 s2 将未初始化并基本上指向垃圾。
EDIT
编辑
You may also want to check out this page which gives hints on how to decipher this particular valgrind error
您可能还想查看此页面,该页面提供了有关如何破译此特定 valgrind 错误的提示
https://computing.llnl.gov/code/memcheck/#deciphering4
https://computing.llnl.gov/code/memcheck/#deciphering4
Addendum
附录
Another common cause for this I've just found is when you pass over some integer constants to a variadic function, which are put on the stack as ints, but when the callee gets it as longs, you've got a problem on 64-bit machines.
我刚刚发现的另一个常见原因是,当您将一些整数常量传递给可变参数函数时,该函数作为整数放在堆栈中,但是当被调用方得到它时,您在 64 上遇到了问题-位机。
I was almost about to give up and just consider valgrind being stupid, then I've realised that simply casting it to long fixes it.
我几乎要放弃并认为 valgrind 很愚蠢,然后我意识到只需将其转换为长时间即可修复它。
So my upshot is: take this messages seriously.
所以我的结论是:认真对待这些信息。
回答by Nick Bolton
If Valgrind states that a value is not initialised, then in 99.5% it is really not initialised. Normally, when compiler reports use of an uninitialised value (-Wuninitialized in GCC), you check for inline unrolls, as your uninitialised value can be declared (and not initialised) for example 10 levels of inline function "calls" (or template unrolls) higher, than actual GCC report. Valgrind does the same, but in runtime. So you should check whole path in which uninitialised value travelled from place of being declared (and not initialised), to the place where it's actually used. The path can be for example: cascade of function calls, where each function passes its arguments (and possibly uninitialised value) to next function. Valgrind will report in last function, when the value is actually used.
如果 Valgrind 声明一个值没有被初始化,那么在 99.5% 中它真的没有被初始化。通常,当编译器报告使用未初始化的值(GCC 中的 -Wuninitialized)时,您会检查内联展开,因为您的未初始化值可以被声明(而不是初始化),例如 10 级内联函数“调用”(或模板展开)高于实际的 GCC 报告。Valgrind 做同样的事情,但在运行时。因此,您应该检查未初始化的值从声明(而不是初始化)的位置到实际使用的位置的整个路径。路径可以是例如:级联函数调用,其中每个函数将其参数(以及可能未初始化的值)传递给下一个函数。Valgrind 将在最后一个函数中报告实际使用该值的时间。
Generally you should not ignore what Valgrind states. Valgrind is not a simple trace program. It can be seen as a virtual machine:
通常,您不应忽略 Valgrind 声明的内容。Valgrind 不是一个简单的跟踪程序。它可以看作是一个虚拟机:
Valgrind is in essence a virtual machine using just-in-time (JIT) compilation techniques, including dynamic recompilation. Nothing from the original program ever gets run directly on the host processor. Instead, Valgrind first translates the program into a temporary, simpler form called Intermediate Representation (IR), which is a processor-neutral, SSA-based form. After the conversion, a tool (see below) is free to do whatever transformations it would like on the IR, before Valgrind translates the IR back into machine code and lets the host processor run it. Even though it could use dynamic translation (that is, the host and target processors are from different architectures), it doesn't. Valgrind recompiles binary code to run on host and target (or simulated) CPUs of the same architecture. (Wikipedia)
Valgrind 本质上是一个使用即时 (JIT) 编译技术(包括动态重新编译)的虚拟机。原始程序中的任何内容都不会直接在主机处理器上运行。相反,Valgrind 首先将程序转换为一种临时的、更简单的形式,称为中间表示 (IR),这是一种与处理器无关、基于 SSA 的形式。转换后,在 Valgrind 将 IR 转换回机器代码并让主机处理器运行它之前,工具(见下文)可以自由地在 IR 上进行任何它想做的转换。即使它可以使用动态转换(即主机和目标处理器来自不同的体系结构),它也没有。Valgrind 重新编译二进制代码以在相同架构的主机和目标(或模拟)CPU 上运行。
回答by bayer
It would be very helpful if you can post more code, especially from the part where valgrind thinks the error is.
如果您可以发布更多代码,尤其是从 valgrind 认为错误所在的部分,那将非常有帮助。
If this happens every time you instantiate the class, you probably forgot to initialize one of the members in the constructor.
如果每次实例化类时都发生这种情况,则您可能忘记初始化构造函数中的成员之一。
And yes: You should worry about this error, those guys can really bite you.
是的:你应该担心这个错误,那些人真的会咬你。
回答by wuxianyun
In 64-bits machine. Usually, int takes 4 bytes in memory. But long will take 8 bytes in memory. So simply refer an int value as long format will cause totally incorrect result. An convert is needed in this situation.
在 64 位机器上。通常, int 在内存中占用 4 个字节。但 long 将在内存中占用 8 个字节。所以只需引用一个 int 值,因为长格式会导致完全不正确的结果。在这种情况下需要转换。
回答by lothar
The error does not seem to come from your code, but a library you are using.
错误似乎不是来自您的代码,而是您正在使用的库。
Valgrind comes with some default error suppression, but that probably does not cover the library you are using.
Valgrind 带有一些默认的错误抑制功能,但这可能不包括您正在使用的库。
The error-checking tools detect numerous problems in the base libraries, such as the GNU C library, and the X11 client libraries, which come pre-installed on your GNU/Linux system. You can't easily fix these, but you don't want to see these errors (and yes, there are many!) So Valgrind reads a list of errors to suppress at startup. A default suppression file is created by the ./configure script when the system is built.
错误检查工具可检测基础库(如 GNU C 库和 X11 客户端库)中的许多问题,这些库预装在您的 GNU/Linux 系统上。您无法轻松修复这些错误,但您不想看到这些错误(是的,有很多!)因此 Valgrind 在启动时读取要抑制的错误列表。./configure 脚本在系统构建时创建默认抑制文件。
You can create your own error suppressionsthat you know are irrelevant to your code.
您可以创建自己的错误抑制,您知道这些错误抑制与您的代码无关。
See the similar SO question Why does Valgrind not like my usage of glutCreateWindow?