让我们从一个例子开始,我想这将证明我正在处理的问题.这是一个简单的测试程序,远非现实,但它确实很好地说明了问题
1 #include2 #include 3 4 struct first { 5 int i_value; 6 }; 7 8 struct second { 9 float f_value; 10 }; 11 12 #define DEFINE_FUNCTION(type, struct_name, field_name) \ 13 void my_ ## type ## _function(struct struct_name *object, type value) \ 14 { \ 15 /* Deliberately read an uninitialized value to make valgrind */ \ 16 /* report the issue */ \ 17 if (object->field_name == -1) \ 18 return; \ 19 object->field_name = value; \ 20 } 21 22 DEFINE_FUNCTION(int, first, i_value); 23 DEFINE_FUNCTION(float, second, f_value); 24 25 void 26 my_test_function(struct first *object, int value) 27 { 28 /* Deliberately read an uninitialized value to make valgrind */ 29 /* report the issue */ 30 if (object->i_value == -1) 31 return; 32 object->i_value = value; 33 } 34 35 int 36 main(void) 37 { 38 struct first frst; 39 struct second scnd; 40 41 my_test_function(&frst, -5); 42 my_int_function(&frst, -2); 43 my_float_function(&scnd, 3.0); 44 45 return 0; 46 }
如果您编译此代码并使用
valgrind --show-origins=yes ./compiled-program
你会看到像这样的输出
==25304== Memcheck, a memory error detector
==25304== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==25304== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==25304== Command: ./macro-valgrind
==25304==
==25304== Conditional jump or move depends on uninitialised value(s)
==25304== at 0x40056F: my_test_function (macro-valgrind.c:30)
==25304== by 0x400597: main (macro-valgrind.c:41)
==25304== Uninitialised value was created by a stack allocation
==25304== at 0x40057F: main (macro-valgrind.c:37)
==25304==
==25304== Conditional jump or move depends on uninitialised value(s)
==25304== at 0x40053A: my_float_function (macro-valgrind.c:23)
==25304== by 0x4005BC: main (macro-valgrind.c:43)
==25304== Uninitialised value was created by a stack allocation
==25304== at 0x40057F: main (macro-valgrind.c:37)
==25304==
==25304== Conditional jump or move depends on uninitialised value(s)
==25304== at 0x400547: my_float_function (macro-valgrind.c:23)
==25304== by 0x4005BC: main (macro-valgrind.c:43)
==25304== Uninitialised value was created by a stack allocation
==25304== at 0x40057F: main (macro-valgrind.c:37)
==25304==
==25304==
==25304== HEAP SUMMARY:
==25304== in use at exit: 0 bytes in 0 blocks
==25304== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==25304==
==25304== All heap blocks were freed -- no leaks are possible
==25304==
==25304== For counts of detected and suppressed errors, rerun with: -v
==25304== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
正如您在上面的valgrind输出中所看到的,报告的第一个未初始化的读取来自my_test_function()
函数,它显示问题发生的确切行.这样修复代码就相当容易了.其他报道显然无法理解.你能用它们做的最好的事情就是知道它是什么功能,但就是这样.
我知道生成的代码令valgrind感到困惑,这就是为什么我的实际问题是,
有没有办法用gcc编译代码,可以帮助valgrind理解这种函数?
Jon Chesterf.. 5
我通过以下方式解决了这种宏引发的调试问题:
1 /评论标准库/第三方#includes
2 /通过gcc -E -C -P,扩展宏
3 /把#include放回去
4 /通过clang格式,打破了很长的行
5 /编译调试信息
程序和以前一样,但是gdb和valgrind引用了扩展的源代码.然后很容易找到错误,然后使用diff工具将其追溯到原始源.
上述听起来很痛苦,但步骤1到步骤4与步骤5一样可编写脚本,因此开发过程中的实际开销很小.这不是我的默认原因是在ide中跳转到错误会将我带到生成的代码,这通常很烦人.
我通过以下方式解决了这种宏引发的调试问题:
1 /评论标准库/第三方#includes
2 /通过gcc -E -C -P,扩展宏
3 /把#include放回去
4 /通过clang格式,打破了很长的行
5 /编译调试信息
程序和以前一样,但是gdb和valgrind引用了扩展的源代码.然后很容易找到错误,然后使用diff工具将其追溯到原始源.
上述听起来很痛苦,但步骤1到步骤4与步骤5一样可编写脚本,因此开发过程中的实际开销很小.这不是我的默认原因是在ide中跳转到错误会将我带到生成的代码,这通常很烦人.