Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I get valgrind to tell me _which_ value is uninitialized?

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?

  • certainly not k;
  • I manually checked (= "stepping through 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()
like image 459
John Perry Avatar asked Sep 19 '18 06:09

John Perry


People also ask

Will we get an error message if we display an uninitialized variable?

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.

What does conditional jump mean in Valgrind?

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".

What is the value of uninitialized local variable?

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.

How do you fix the conditional jump in Valgrind?

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.

What is –track-origins=Yes in Valgrind?

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:

How to suppress contents of an executable using Valgrind?

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!

What causes Valgrind to fail to detect memory changes?

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.

Does it matter if a conditional jump depends on uninitialised values?

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.


1 Answers

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.

like image 153
ks1322 Avatar answered Nov 15 '22 23:11

ks1322