简体   繁体   中英

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()

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.

From the Valgrind documentation ,

4.2.2. Use of uninitialised values
...

Sources of uninitialised data tend to be:
- Local variables in procedures which have not been initialised, as in the example above.
- The contents of heap blocks (allocated with malloc, new, or a similar function) before you (or a constructor) write something there.

You have:

==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)

So it is very likely that the malloc used by GODA<unsigned int>::allocate_new_block() is causing this error.

You could use clang-tidy as an alternative to find uninitialized variables. QtCreator 4.7 has full integration of clang-tidy, select "Clang-Tidy and Clazy" in the debug pane, press run, select the file(s) you want to test.

You can use gdb+vgdb+valgrind to debug your program under valgrind.

Then, when valgrind stops on the error reported above, you can examine the definedness of the variables you are interested in using the monitor request 'xb' or 'get_vbits' by asking the adress of the variable, and then examining the vbits for the size of the variable.

For example:

p &searching
=> 0xabcdef
monitor xb 0xabcdef 1
=> will show you the value of searching and the related vbits.

For more details, see 'Debugging your program using Valgrind gdbserver and GDB' http://www.valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver and 'Memcheck Monitor Commands' http://www.valgrind.org/docs/manual/mc-manual.html#mc-manual.monitor-commands

You need to understand how memcheck works. In order to avoid generating excessive errors, uninitialized values don't get flagged until they have a possible impact on your code. The uninitialized information gets propagated by assignments.

// if ord_deg returns something that is uninitialized, dtk and/or duk will be
// flagged internally as uninitialized but no error issued
DEG_TYPE dtk = t.ord_deg();
DEG_TYPE duk = u.ord_deg();
// again transitively if either dtk or duk is flagged as uninitialized then
// searching will be flagged as uninitialized, and again no error issued
bool searching = dtk == duk;
// if nv() returns something that is uninitialized, n will be
// flagged internally as unintialized
NVAR_TYPE n = t.nv();
// k is flagged as initialized
NVAR_TYPE k = 0;
// OK now the values of searching and n affect your code flow
// if either is uninitialized then memcheck will issue an error
for (/* */; searching and k < n; ++k) { // this is line 71

You are looking at wrong stack trace.

Valgrind tells you that uninitialized value was created by a heap allocation:

==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)

You can omit a few top stack frames from third party library code, because it is less likely that the error is in third party code. You should look more closely at this stack frame, which appears to be your code:

==24860==    by 0x402A0E: M::init(unsigned long) (m.cpp:63)

Most likely uninitialized variable should be in m.cpp:63 line of code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM