我可以让 valgrind 告诉我_哪个_值未初始化吗?
Can I get valgrind to tell me _which_ value is uninitialized?
我运行valgrind
上的部分代码如下:
valgrind --tool=memcheck --leak-check=full --track-origins=yes ./test
它returns出现以下错误:
==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
;
- 我手动检查(="stepping through
gdb
")t
的构造函数初始化了t.nv()
返回的值,所以肯定不是n
(事实上n
设置为6,正确值);
searching
由dtk
和duk
决定,但我也手动检查了t
和u
的构造函数初始化值由 .ord_deg()
返回(实际上 dtk
和 duk
都设置为 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);
}
这是 class 中的数据,添加注释显示它的初始化位置:
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()
来自 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.
你有:
==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)
所以很可能是GODA<unsigned int>::allocate_new_block()
使用的malloc
导致了这个错误。
您可以使用 clang-tidy 作为查找未初始化变量的替代方法。
QtCreator 4.7 完全集成了 clang-tidy,select "Clang-Tidy and Clazy" 在调试窗格中,按 运行,select 您要测试的文件。
您需要了解 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
您正在查看错误的堆栈跟踪。
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
代码行中。
您可以使用gdb+vgdb+valgrind在valgrind下调试您的程序。
然后,当 valgrind 因上面报告的错误而停止时,您可以检查
您对使用监视器请求感兴趣的变量的定义
'xb' 或 'get_vbits' 通过询问变量的地址,然后检查
变量大小的 vbits。
例如:
p &searching
=> 0xabcdef
monitor xb 0xabcdef 1
=> will show you the value of searching and the related vbits.
有关详细信息,请参阅 'Debugging your program using Valgrind gdbserver and GDB' http://www.valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver
和 'Memcheck Monitor Commands' http://www.valgrind.org/docs/manual/mc-manual.html#mc-manual.monitor-commands
Is there some option that will tell valgrind to report which precise
value it thinks is uninitialized?
您最好使用 --track-origins=yes
(您已经在使用该选项)。 Valgrind 只会告诉您未初始化值的大概位置(根据 Valgrind 的来源),但不会告诉您确切的变量名称。 --track-origins
见 Valgrind manual:
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.
我运行valgrind
上的部分代码如下:
valgrind --tool=memcheck --leak-check=full --track-origins=yes ./test
它returns出现以下错误:
==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
; - 我手动检查(="stepping through
gdb
")t
的构造函数初始化了t.nv()
返回的值,所以肯定不是n
(事实上n
设置为6,正确值); searching
由dtk
和duk
决定,但我也手动检查了t
和u
的构造函数初始化值由.ord_deg()
返回(实际上dtk
和duk
都设置为 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);
}
这是 class 中的数据,添加注释显示它的初始化位置:
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()
来自 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.
你有:
==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)
所以很可能是GODA<unsigned int>::allocate_new_block()
使用的malloc
导致了这个错误。
您可以使用 clang-tidy 作为查找未初始化变量的替代方法。 QtCreator 4.7 完全集成了 clang-tidy,select "Clang-Tidy and Clazy" 在调试窗格中,按 运行,select 您要测试的文件。
您需要了解 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
您正在查看错误的堆栈跟踪。
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
代码行中。
您可以使用gdb+vgdb+valgrind在valgrind下调试您的程序。
然后,当 valgrind 因上面报告的错误而停止时,您可以检查 您对使用监视器请求感兴趣的变量的定义 'xb' 或 'get_vbits' 通过询问变量的地址,然后检查 变量大小的 vbits。
例如:
p &searching
=> 0xabcdef
monitor xb 0xabcdef 1
=> will show you the value of searching and the related vbits.
有关详细信息,请参阅 'Debugging your program using Valgrind gdbserver and GDB' http://www.valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver 和 'Memcheck Monitor Commands' http://www.valgrind.org/docs/manual/mc-manual.html#mc-manual.monitor-commands
Is there some option that will tell valgrind to report which precise value it thinks is uninitialized?
您最好使用 --track-origins=yes
(您已经在使用该选项)。 Valgrind 只会告诉您未初始化值的大概位置(根据 Valgrind 的来源),但不会告诉您确切的变量名称。 --track-origins
见 Valgrind manual:
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.