190

因此,我从 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 侦探工作的情况下捕获错误值的最佳方法是什么?

更新:

我发现了问题所在,但奇怪的是,第一次使用 bad value 时 valgrind 没有报告。它用于乘法函数:

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

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

4

2 回答 2

262

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

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

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

Valgrind 常见问题解答

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

于 2010-04-10T06:40:49.030 回答
25

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

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

编辑

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

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

于 2010-04-10T06:14:03.380 回答