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


166

因此,我从valgrind那里得到了一些神秘的未初始化的值消息,关于错误值的起源一直是个谜。

似乎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)

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

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

就这样 有什么我想念的吗?在不必诉诸于超长的printf侦探工作的情况下捕捉不良价值的最佳方法是什么?

更新:

我发现了问题所在,但奇怪的是,当首次使用该错误值时,valgrind并未报告该错误。它用于乘法功能:

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

speedfac是一个单元化的浮点数。但是,当时没有报告,并且直到要打印该值时才出现错误。.是否为valgrind设置了更改此行为的方法?

Answers:


230

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

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

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

来自Valgrind常见问题解答

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


1
使用此功能的最低valgrind版本是什么?我正在使用3.3.0,它似乎不喜欢该选项。
罗伯特·S·巴恩斯

8
@Robert:--track-origins在valgrind 3.4.0中添加
mark4o 2010年

20

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

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

编辑

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

似乎并没有立即警告您,这似乎是违反直觉的,但是正如mark4o所指出的,这样做是因为未初始化的值始终在C中使用(例如:在结构中填充,realloc()调用等),因此不会出现这些警告。由于误报频率非常有用。


谢谢。我只是发现了什么是错误的,但奇怪的是,Valgrind的没有报告unitialised价值的东西,直到它被用于其他地方..
kamziro

那是故意的。如果只是复制或传递未初始化的值导致错误报告,那么您将始终从填充结构中获取它们。
mark4o
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.