我可以让valgrind告诉我哪个值未初始化吗?

时间:2018-09-19 06:15:52

标签: c++ initialization valgrind

我在某些代码上运行了valgrind,如下所示:

valgrind --tool=memcheck --leak-check=full --track-origins=yes ./test

它返回以下错误:

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

因此第71行有错误。好,很好。以下是通往po.cpp第71行的行(第71行位于最后):

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

确定,那么第71行的哪个值未初始化?

  • 肯定不是k;
  • 我手动检查(=“逐步完成gdb”),t的构造函数初始化了t.nv()返回的值,因此肯定不会n(在事实n设置为6,即正确值);
  • searchingdtkduk决定,但我还手动检查了tu的构造函数初始化的值是由.ord_deg()返回(实际上dtkduk都设置为3,即正确的值)。

我在这里完全不知所措。是否有一些选项可以告诉valgrind报告它认为尚未初始化的哪个精确值

更新

为回答一个问题,这是test.cpp的第61行:

M s { 1, 0, 5, 2, 0 };

因此它使用初始化列表进行构造。这是构造函数:

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);
}

这是类中的数据,添加注释以显示其初始化位置:

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

6 个答案:

答案 0 :(得分:5)

  

是否有一些选项可以告诉valgrind报告精确度   它认为未初始化的值?

最好的办法是使用--track-origins=yes(您已经在使用此选项)。 Valgrind将仅告诉您未初始化值的大概位置(以Valgrind表示),而不告诉您确切的变量名称。请参见Valgrind manual中的--track-origins

  

设置为“是”时,Memcheck会跟踪所有对象的来源   未初始化的值。然后,当未初始化的值错误是   报告,Memcheck将尝试显示该值的来源。起源   可以是以下四个位置之一:堆块,堆栈   分配,客户请求或其他各种来源(例如,   致电brk)。

     

对于源自堆块的未初始化值,Memcheck显示   分配块的位置。对于原始的未初始化值   从堆栈分配中,Memcheck可以告诉您哪个函数   分配了值,但仅此而已-通常它会向您显示   该函数的右括号的源位置。那么你   应该仔细检查函数的所有局部变量   正确初始化。

答案 1 :(得分:3)

来自Valgrind documentation

  

4.2.2。使用未初始化的值
  ...

     

未初始化数据的来源通常是:
  -如上例所示,未初始化的过程中的局部变量。
  -在您(或构造函数)在其中写入内容之前,堆块的内容(与malloc,new或类似的函数一起分配)。

您有:

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

因此,malloc使用的GODA<unsigned int>::allocate_new_block()很有可能导致此错误。

答案 2 :(得分:2)

您可以使用clang-tidy作为查找未初始化变量的替代方法。 QtCreator 4.7完全集成了clang-tidy,请在调试窗格中选择“ Clang-Tidy和Clazy”,按运行,然后选择要测试的文件。

答案 3 :(得分:2)

您可以使用gdb + vgdb + valgrind在valgrind下调试程序。

然后,当valgrind因以上报告的错误而停止时,您可以检查 您对使用监视请求感兴趣的变量的定义性 通过询问变量的地址,然后检查“ xb”或“ get_vbits” 变量大小的位。

例如:

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

有关更多详细信息,请参见“使用Valgrind gdbserver和GDB调试程序” http://www.valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver 和“ Memcheck监控器命令” http://www.valgrind.org/docs/manual/mc-manual.html#mc-manual.monitor-commands

答案 4 :(得分:1)

您需要了解memcheck的工作方式。为了避免产生过多的错误,只有在未初始化的值可能对您的代码产生影响之前,才对其进行标记。未初始化的信息通过分配传播。

// 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

答案 5 :(得分:1)

您正在查看错误的堆栈跟踪。

Valgrind告诉您未初始化的值是由堆分配创建的:

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

您可以从第三方库代码中省略一些顶部堆栈框架,因为错误不太可能出自第三方代码。您应该更仔细地看一下这个堆栈框架,它看起来像是您的代码:

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

最可能的未初始化变量应位于代码的m.cpp:63行中。