Valgrind tool suite提供一些debugging和profiling工具,来让你的程序跑的更快,更正确。其中最流行的工具是memcheck,它能检测C/C++程序内存相关的错误,这些错误可能导致程序奔溃和不可预测的行为。
最好使用-g -O0选项编译程序。这样valgrind的报告更准确。
valgrind尽可能设计成 non-intrusive,它直接执行要调试的程序,不需要修改代码或重新编译。使用下面的方法开始调试程序:
1 | $ valgrind [valgrind-options] your-prog [your-prog-options] |
最重要的选项是--tool,它指定要运行的valgrind工具。memcheck是默认的工具。程序运行在valgrind core提供的一个人造的(synthetic)CPU上。valgrind在执行指令前,将指令发送给tool,tool添加自己的指令,然后返还给core执行。memcheck工具检查每一条内存访问指令。因而可以获得非法的内存读写。大量的instrumentation code被添加,导致valgrind运行程序慢了10到50倍。
程序运行后,只有一个valgrind.bin进程,如下:
1 2 3 4 | $ valgrind . /a .out $ ps aux | grep a.out yuanjia+ 10846 112 1.2 120364 50596 pts /4 Sl+ 07:37 0:06 /usr/bin/valgrind .bin . /a .out |
top可以看到原本的两个线程:
1 2 3 4 5 6 7 8 9 10 | $ top -H -p `pidof valgrind.bin` top - 07:40:04 up 21 days, 5:59, 8 users, load average: 0.90, 0.36, 0.14 Threads: 2 total, 1 running, 1 sleeping, 0 stopped, 0 zombie %Cpu(s): 50.2 us, 0.2 sy, 0.0 ni, 49.0 id, 0.0 wa, 0.0 hi, 0.3 si, 0.3 st KiB Mem : 4039152 total, 287444 free, 495916 used, 3255792 buff/cache KiB Swap: 4038652 total, 4034800 free, 3852 used. 3245980 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 10847 yuanjia+ 20 0 120364 50596 4580 R 99.9 1.3 2:07.44 memcheck-amd64- 10846 yuanjia+ 20 0 120364 50596 4580 S 0.0 1.3 0:00.95 memcheck-amd64- |
但是线程名被修改了。
可以给valgrind.bin发送信号,这个信号就好像发送给a.out一样。当然不可以捕获信号只能发送给valgrind.bin。
memcheck工具可以:
1 检查非法内存读写,如堆内存越界读写,栈顶非法写、访问释放后的内存。
2 使用未定义的变量。
3 不正确的堆内存释放,如重复释放,释放非堆内存等。
4 memcpy等函数src和dst重叠。
5 传一个非法的size给分配函数。
6 内存泄漏。
测试程序代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <stdlib.h> void f( void ) { int * x = malloc (10 * sizeof ( int )); x[10] = 0; // problem 1: heap block overrun } // problem 2: memory leak -- x not freed int main( void ) { f(); return 0; } |
这段程序越界访问,并且没有释放分配的内存。
选项:
--undef-value-errors=no,不检查未定义值访问。
--leak-check=no,不检查内存泄漏。
当定位堆异常时,通常不要做这两个检查,否则打印输出很多。
使用valgrind调试:
$ valgrind --undef-value-errors=no --leak-check=no ./a.out
==11481== Memcheck, a memory error detector
==11481== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11481== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==11481== Command: ./a.out
==11481==
==11481== Invalid write of size 4
==11481== at 0x108668: f (in /work/test/valgrid/a.out)
==11481== by 0x108679: main (in /work/test/valgrid/a.out)
==11481== Address 0x522d068 is 0 bytes after a block of size 40 alloc'd
==11481== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11481== by 0x10865B: f (in /work/test/valgrid/a.out)
==11481== by 0x108679: main (in /work/test/valgrid/a.out)
==11481==
==11481==
==11481== HEAP SUMMARY:
==11481== in use at exit: 40 bytes in 1 blocks
==11481== total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==11481==
==11481== For a detailed leak analysis, rerun with: --leak-check=full
==11481==
上述日志详细打印了,非法访问了哪个内存。这个内存是在哪里分配的,
参考资料:
https://www.valgrind.org/docs/manual/valgrind_manual.pdf