I ran valgrind
on some code as follows:
valgrind --tool=memcheck --leak-check=full --track-origins=yes ./test
It returns the following error:
==24860== Conditional jump or move depends on uninitialised value(s)
==24860== at 0x4081AF: GG::fl(M const&, M const&) const (po.cpp:71)
==24860== by 0x405CDB: MO::fle(M const&, M const&) const (m.cpp:708)
==24860== by 0x404310: M::operator>=(M const&) const (m.cpp:384)
==24860== by 0x404336: M::operator<(M const&) const (m.cpp:386)
==24860== by 0x4021FD: main (test.cpp:62)
==24860== Uninitialised value was created by a heap allocation
==24860== at 0x4C2EBAB: malloc (vg_replace_malloc.c:299)
==24860== by 0x40653F: GODA<unsigned int>::allocate_new_block() (goda.hpp:82)
==24860== by 0x406182: GODA<unsigned int>::GODA(unsigned long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) (goda.hpp:103)
==24860== by 0x402A0E: M::init(unsigned long) (m.cpp:63)
==24860== by 0x403831: M::M(std::initializer_list<unsigned int>, MO const*) (m.cpp:248)
==24860== by 0x401B56: main (test.cpp:31)
So line 71 has an error. OK, great. Here are the lines leading up to line 71 of po.cpp
(line 71 is last):
DEG_TYPE dtk = t.ord_deg();
DEG_TYPE duk = u.ord_deg();
bool searching = dtk == duk;
NVAR_TYPE n = t.nv();
NVAR_TYPE k = 0;
for (/* */; searching and k < n; ++k) { // this is line 71
OK, so which value of line 71 is uninitialized?
k
;gdb
") that t
's constructor initializes the value that is returned by t.nv()
, so certainly not n
(in fact n
is set to 6, the correct value);searching
is determined by dtk
and duk
, but I also manually checked that t
's and u
's constructors initialize the values that are returned by .ord_deg()
(in fact both dtk
and duk
are set to 3, the correct value).I'm at a complete loss here. Is there some option that will tell valgrind
to report which precise value it thinks is uninitialized?
Update
In answer to one question, here is line 61 of test.cpp
:
M s { 1, 0, 5, 2, 0 };
So it constructs using an initializer list. Here's that constructor:
M::M(
initializer_list<EXP_TYPE> p, const MO * ord
) {
common_init(ord);
init_e(p.size());
NVAR_TYPE i = 0;
last = 0;
for (
auto pi = p.begin();
pi != p.end();
++pi
) {
if (*pi != 0) {
e[last] = i;
e[last + 1] = *pi;
last += 2;
}
++i;
}
ord->set_data(*this);
}
Here's the data in the class, adding comments showing where it's initialized:
NVAR_TYPE n; // init_e()
EXP_TYPE * e; // common_init()
NVAR_TYPE last; // common_init()
DEG_TYPE od; // common_init(), revised in ord->set_data()
const MO * o; // common_init()
MOD * o_data; // common_init(), revised in ord->set_data()
An uninitialized variable has an undefined value, often corresponding to the data that was already in the particular memory location that the variable is using. This can lead to errors that are very hard to detect since the variable's value is effectively random, different values cause different errors or none at all.
Uninitialized value errors The error message "Conditional jump or move depends on uninitialized value(s)" essentially means Valgrind has determined that the result of your program depends on uninitialized memory. Sometimes you will also see the message "Use of uninitialized value of size N".
Uninitialized local variable is a variable that was declared inside a function but it was not assigned a value. It contains default value for that data type. Using an uninitialized variable in an expression may give unexpected results or cause compilation errors.
Conditional jump or move depends on uninitialized value(s) This error is caused if you forget to initialize variables before using or accessing them. You can usually re-run valgrind with the flag --track-origins=yes to see where the uninitialized value came from.
However, Valgrind 3.4.0 introduced a new option, –track-origins=yes. What it does is, for every undefined value, it tracks where the undefinedness originated. The origin is usually a stack or heap allocation. With –track-origins=yes, each complaint about an undefined value will be augmented with origin information like this:
For example, if your executable is a.out, create ./val.supp file with the content and run valgrind --suppressions=./val.supp ./a.out. Thanks for contributing an answer to Stack Overflow!
Mats Palmgren investigated, but wasn’t able to determine the cause. His conclusion was: The only possible explanations I can think of is either a bug in valgrind itself, or we make bogus VALGRIND_* calls to misinform it about the status of this memory.
What does matter is that when Memcheck complains that a “Conditional jump or move depends on uninitialised value (s)” — “undefined” would arguably be better in that message than “uninitialised”, but that message hasn’t changed for years — it’s determined that an undefined value is being used in a dangerous way.
Is there some option that will tell valgrind to report which precise value it thinks is uninitialized?
The best you can do is to use --track-origins=yes
(you already using this option). Valgrind will tell you only approximate location of uninitialised values (origin in terms of Valgrind), but not exact variable name. See Valgrind manual for --track-origins
:
When set to yes, Memcheck keeps track of the origins of all uninitialised values. Then, when an uninitialised value error is reported, Memcheck will try to show the origin of the value. An origin can be one of the following four places: a heap block, a stack allocation, a client request, or miscellaneous other sources (eg, a call to brk).
For uninitialised values originating from a heap block, Memcheck shows where the block was allocated. For uninitialised values originating from a stack allocation, Memcheck can tell you which function allocated the value, but no more than that -- typically it shows you the source location of the opening brace of the function. So you should carefully check that all of the function's local variables are initialised properly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With