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在第一次使用坏值时并没有报告。它用于乘法函数:
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是否会改变这种行为?
2 个解决方案
#1
198
Use the valgrind option --track-origins=yes
to 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.
至于对未初始化的内存值副本的快速报告,已经多次建议这样做。不幸的是,几乎所有的程序都合法地复制了周围的未初始化的内存值(因为编译器使用pad结构来保持对齐),而且急切的检查会导致数百个错误的判断。因此,此时的Memcheck不支持紧急检查。
#2
17
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 move based 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 mark4o pointed 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()调用,等等)。这些警告不会由于假阳性频率非常有用。
#1
198
Use the valgrind option --track-origins=yes
to 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.
至于对未初始化的内存值副本的快速报告,已经多次建议这样做。不幸的是,几乎所有的程序都合法地复制了周围的未初始化的内存值(因为编译器使用pad结构来保持对齐),而且急切的检查会导致数百个错误的判断。因此,此时的Memcheck不支持紧急检查。
#2
17
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 move based 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 mark4o pointed 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()调用,等等)。这些警告不会由于假阳性频率非常有用。