C++ 查明“条件跳转或移动取决于未初始化的值” valgrind 消息

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2612447/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:05:03  来源:igfitidea点击:

pinpointing "conditional jump or move depends on uninitialized value(s)" valgrind message

c++valgrind

提问by kamziro

So I've been getting some mysterious uninitialized values message from valgrind and it's been quite the mystery as of where the bad value originated from.

因此,我从 valgrind 收到了一些神秘的未初始化值消息,关于坏值的来源一直是个谜。

Seems that valgrind shows the place where the unitialised value ends up being used, but not the origin of the uninitialised value.

似乎 valgrind 显示了未初始化值最终被使用的地方,而不是未初始化值的来源。

==11366== Conditional jump or move depends on uninitialised value(s)
==11366==    at 0x43CAE4F: __printf_fp (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43C6563: vfprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43EAC03: vsnprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x42D475B: (within /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E2C9B: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E31B4: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42EE56F: std::ostream& std::ostream::_M_insert<double>(double) (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)
==11366==    by 0x810B9F1: Snake::Snake::update() (snake.cpp:257)
==11366==    by 0x81113C1: SnakeApp::updateState() (snakeapp.cpp:224)
==11366==    by 0x8120351: RoenGL::updateState() (roengl.cpp:1180)
==11366==    by 0x81E87D9: Roensachs::update() (rs.cpp:321)

As can be seen, it gets quite cryptic.. especially because when it's saying by Class::MethodX, it sometimes points straight to ostream etc. Perhaps this is due to optimization?

可以看出,它变得非常神秘......特别是因为当它说 Class::MethodX 时,它有时直接指向 ostream 等。也许这是由于优化?

==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)

Just like that. Is there something I'm missing? What is the best way to catch bad values without having to resort to super-long printf detective work?

就这样。有什么我想念的吗?在不必求助于超长的 printf 侦探工作的情况下,捕获错误值的最佳方法是什么?

Update:

更新:

I found out what was wrong, but the strange thing is, valgrind did not report it when the bad value was first used. It was used in a multiplication function:

我发现哪里不对了,但奇怪的是,valgrind 在第一次使用 bad 值时并没有报告。它用于乘法函数:

movespeed = stat.speedfactor * speedfac * currentbendfactor.val;

Where speedfac was an unitialised float. However, at that time it was not reported and not until the value is to be printed that I get the error.. Is there a setting for valgrind to change this behavior?

speedfac 是一个统一的浮点数。但是,当时没有报告它,直到要打印该值时才出现错误.. valgrind 是否有设置可以更改此行为?

回答by mark4o

Use the valgrind option --track-origins=yesto have it track the origin of uninitialized values. This will make it slower and take more memory, but can be very helpful if you need to track down the origin of an uninitialized value.

使用 valgrind 选项--track-origins=yes让它跟踪未初始化值的来源。这将使其变慢并占用更多内存,但如果您需要追踪未初始化值的来源,这将非常有用。

Update:Regarding the point at which the uninitialized value is reported, the valgrind manual states:

更新:关于报告未初始化值的点,valgrind 手册指出

It is important to understand that your program can copy around junk (uninitialised) data as much as it likes. Memcheck observes this and keeps track of the data, but does not complain. A complaint is issued only when your program attempts to make use of uninitialised data in a way that might affect your program's externally-visible behaviour.

重要的是要了解您的程序可以随心所欲地复制垃圾(未初始化)数据。Memcheck 观察到这一点并跟踪数据,但没有抱怨。只有当您的程序试图以可能影响您程序的外部可见行为的方式使用未初始化的数据时,才会发出投诉。

From the Valgrind FAQ:

来自Valgrind 常见问题解答

As for eager reporting of copies of uninitialised memory values, this has been suggested multiple times. Unfortunately, almost all programs legitimately copy uninitialised memory values around (because compilers pad structs to preserve alignment) and eager checking leads to hundreds of false positives. Therefore Memcheck does not support eager checking at this time.

至于急切地报告未初始化的内存值的副本,这已被多次建议。不幸的是,几乎所有程序都会合法地复制未初始化的内存值(因为编译器填充结构以保持对齐)并且急切检查会导致数百个误报。因此 Memcheck 目前不支持 Eager Check。

回答by RarrRarrRarr

What this means is that you are trying to print out/output a value which is at least partially uninitialized. Can you narrow it down so that you know exactly what value that is? After that, trace through your code to see where it is being initialized. Chances are, you will see that it is not being fully initialized.

这意味着您正在尝试打印/输出一个至少部分未初始化的值。你能缩小范围以便你确切地知道那是什么价值吗?之后,跟踪您的代码以查看它被初始化的位置。很有可能,您会看到它没有被完全初始化。

If you need more help, posting the relevant sections of source code might allow someone to offer more guidance.

如果您需要更多帮助,发布源代码的相关部分可能会让某人提供更多指导。

EDIT

编辑

I see you've found the problem. Note that valgrind watches for Conditional jump or movebased on unitialized variables. What that means is that it will only give out a warning if the execution of the program is altered due to the uninitialized value (ie. the program takes a different branch in an if statement, for example). Since the actual arithmetic did not involve a conditional jump or move, valgrind did not warn you of that. Instead, it propagated the "uninitialized" status to the result of the statement that used it.

我看你已经发现问题了。请注意,valgrind根据未初始化的变量监视条件跳转或移动。这意味着它只会在程序的执行由于未初始化的值而改变时发出警告(例如,程序在 if 语句中采用不同的分支)。由于实际算术不涉及条件跳转或移动,因此 valgrind 没有警告您。相反,它将“未初始化”状态传播到使用它的语句的结果。

It may seem counterintuitive that it does not warn you immediately, but as mark4opointed out, it does this because uninitialized values get used in C all the time (examples: padding in structures, the realloc()call, etc.) so those warnings would not be very useful due to the false positive frequency.

它不会立即警告您似乎有悖常理,但正如mark4o指出的那样,它这样做是因为 C 中一直使用未初始化的值(例如:结构中的填充、realloc()调用等),因此这些警告不会由于误报频率非常有用。