内存动态分析工具Valgrind初探

来源:互联网 发布:淘宝网死飞自行车 编辑:程序博客网 时间:2024/05/15 11:40

    Valgrind是一款开源内存使用问题检测工具,3.7.0版本的下载地址为http://valgrind.org/downloads/valgrind-3.7.0.tar.bz2。

    今天,对它做一下初步的测试,测试平台Ubuntu 10.04 64bit。

    下载完成后,解压源码,执行./configure;make;make install后,默认安装到/usr/local/bin下,执行:    

valgrind ls -l

    提示:

==14336== Memcheck, a memory error detector==14336== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.==14336== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info==14336== Command: ls -l==14336==valgrind:  Fatal error at startup: a function redirectionvalgrind:  which is mandatory for this platform-tool combinationvalgrind:  cannot be set up.  Details of the redirection are:valgrind:valgrind:  A must-be-redirected functionvalgrind:  whose name matches the pattern:      strlenvalgrind:  in an object with soname matching:   ld-linux-x86-64.so.2valgrind:  was not found whilst processingvalgrind:  symbols from the object with soname: ld-linux-x86-64.so.2valgrind:valgrind:  Possible fixes: (1, short term): install glibc's debuginfovalgrind:  package on this machine.  (2, longer term): ask the packagersvalgrind:  for your Linux distribution to please in future ship a non-valgrind:  stripped ld.so (or whatever the dynamic linker .so is called)valgrind:  that exports the above-named function using the standardvalgrind:  calling conventions for this platform.  The package you needvalgrind:  to install for fix (1) is calledvalgrind:valgrind:    On Debian, Ubuntu:                 libc6-dbgvalgrind:    On SuSE, openSuSE, Fedora, RHEL:   glibc-debuginfovalgrind:valgrind:  Cannot continue -- exiting now.  Sorry.
    大概是说我的glibc是个strip后的版本,需要下载debug版,debug版的名字是libc6-dbg。

    执行:

sudo apt-get install libc6-dbg

    再次执行valgrind ls -l,输出:

==14378== Memcheck, a memory error detector==14378== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.==14378== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info==14378== Command: ls -l==14378==total 108drwxr-xr-x   2 root root  4096 2012-07-13 03:26 bindrwxr-xr-x   3 root root  4096 2012-07-13 07:36 bootdrwxr-xr-x   2 root root  4096 2012-07-13 07:06 cdromdrwxr-xr-x  17 root root  3620 2012-07-24 03:00 devdrwxr-xr-x 128 root root 12288 2012-07-24 03:06 etcdrwxr-xr-x   3 root root  4096 2012-07-13 08:16 homelrwxrwxrwx   1 root root    33 2012-07-13 07:07 initrd.img -> boot/initrd.img-2.6.32-38-genericdrwxr-xr-x  16 root root 12288 2012-07-13 03:23 libdrwxr-xr-x   2 root root  4096 2012-07-13 03:24 lib32lrwxrwxrwx   1 root root     4 2012-07-13 07:03 lib64 -> /libdrwx------   2 root root 16384 2012-07-13 07:03 lost+founddrwxr-xr-x   4 root root  4096 2012-07-13 02:13 mediadrwxr-xr-x   2 root root  4096 2012-02-03 04:21 mntdrwxr-xr-x   2 root root  4096 2012-07-13 07:03 optdr-xr-xr-x 182 root root     0 2012-07-24 02:58 procdrwx------   8 root root  4096 2012-07-24 21:25 rootdrwxr-xr-x   2 root root  4096 2012-07-16 01:21 sbindrwxr-xr-x   2 root root  4096 2009-12-05 17:25 selinuxdrwxr-xr-x   2 root root  4096 2012-07-13 07:03 srvdrwxr-xr-x  13 root root     0 2012-07-24 02:58 sysdrwxrwxrwx   2 root root  4096 2012-07-16 01:39 tftpbootdrwxrwxrwt  14 root root  4096 2012-07-24 21:31 tmpdrwxr-xr-x  11 root root  4096 2012-07-13 03:23 usrdrwxr-xr-x  15 root root  4096 2012-07-13 07:31 varlrwxrwxrwx   1 root root    30 2012-07-13 07:07 vmlinuz -> boot/vmlinuz-2.6.32-38-genericdrwxrwxrwx   6 root root  4096 2012-07-24 03:02 work==14378====14378== HEAP SUMMARY:==14378==     in use at exit: 20,081 bytes in 58 blocks==14378==   total heap usage: 1,798 allocs, 1,740 frees, 164,568 bytes allocated==14378====14378== LEAK SUMMARY:==14378==    definitely lost: 240 bytes in 3 blocks==14378==    indirectly lost: 480 bytes in 20 blocks==14378==      possibly lost: 0 bytes in 0 blocks==14378==    still reachable: 19,361 bytes in 35 blocks==14378==         suppressed: 0 bytes in 0 blocks==14378== Rerun with --leak-check=full to see details of leaked memory==14378====14378== For counts of detected and suppressed errors, rerun with: -v==14378== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
    看来ls这个命令是没有任何内存问题的。。。

    好了,我们自己写一段吧:

#include <string.h>/*  * ===  FUNCTION  ====================================================================== *         Name:  bug *  Description:   * ===================================================================================== */void bug ( ){int a[100], * b, * c;b=new int[100];//memset(a, 0, 2000);a[100]=0;b[100]=0;*c=0;}/* -----  end of function bug  ----- *//*  * ===  FUNCTION  ====================================================================== *         Name:  main *  Description:   * ===================================================================================== */int main ( int argc, char *argv[] ){bug();return 0;}/* ----------  end of function main  ---------- */

    这段代码囊括了经常遇到的内存问题:泄漏、野指针和越界访问(真恶心,我写的时候有点想吐)。那么用valgrind测试的结果如何呢?(编译时请加上-ggdb -O0,以便valgrind能够定位到具体出问题的位置)

==14525== Memcheck, a memory error detector==14525== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.==14525== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info==14525== Command: ./membug==14525====14525== Invalid write of size 4==14525==    at 0x40064E: bug() (membug.cpp:14)==14525==    by 0x400673: main (membug.cpp:25)==14525==  Address 0x59601d0 is 0 bytes after a block of size 400 alloc'd==14525==    at 0x4C28112: operator new[](unsigned long) (vg_replace_malloc.c:348)==14525==    by 0x400638: bug() (membug.cpp:11)==14525==    by 0x400673: main (membug.cpp:25)==14525====14525== Use of uninitialised value of size 8==14525==    at 0x400658: bug() (membug.cpp:15)==14525==    by 0x400673: main (membug.cpp:25)==14525====14525== Invalid write of size 4==14525==    at 0x400658: bug() (membug.cpp:15)==14525==    by 0x400673: main (membug.cpp:25)==14525==  Address 0x0 is not stack'd, malloc'd or (recently) free'd==14525====14525====14525== Process terminating with default action of signal 11 (SIGSEGV)==14525==  Access not within mapped region at address 0x0==14525==    at 0x400658: bug() (membug.cpp:15)==14525==    by 0x400673: main (membug.cpp:25)==14525==  If you believe this happened as a result of a stack==14525==  overflow in your program's main thread (unlikely but==14525==  possible), you can try to increase the size of the==14525==  main thread stack using the --main-stacksize= flag.==14525==  The main thread stack size used in this run was 8388608.==14525====14525== HEAP SUMMARY:==14525==     in use at exit: 400 bytes in 1 blocks==14525==   total heap usage: 1 allocs, 0 frees, 400 bytes allocated==14525====14525== 400 bytes in 1 blocks are still reachable in loss record 1 of 1==14525==    at 0x4C28112: operator new[](unsigned long) (vg_replace_malloc.c:348)==14525==    by 0x400638: bug() (membug.cpp:11)==14525==    by 0x400673: main (membug.cpp:25)==14525====14525== LEAK SUMMARY:==14525==    definitely lost: 0 bytes in 0 blocks==14525==    indirectly lost: 0 bytes in 0 blocks==14525==      possibly lost: 0 bytes in 0 blocks==14525==    still reachable: 400 bytes in 1 blocks==14525==         suppressed: 0 bytes in 0 blocks==14525====14525== For counts of detected and suppressed errors, rerun with: -v==14525== Use --track-origins=yes to see where uninitialised values come from==14525== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 2 from 2)Segmentation fault
    可以看出valgrind定位出了第11行的内存泄漏,第14行的越界访问,第15行的野指针访问,但对13行的数组越界无动于衷。实际运行可以发现,对数组a的也并未引起程序异常,这是为什么呢?原因是因为数组a是在栈中分配的空间,对a[100]的写入并未引起程序栈出现异常,可以说仅在这个时候没引起异常。为了加大栈溢出访问的影响,可以改成memset(a, 0, 2000),运行后发现valgrind会发现问题,可是由于栈数据丢失,已经不能分析出有问题的地方了。
    Valgrind支持x86平台32和64位,支持arm32和64位,但是不支持mips,最近做的项目都是mips的,可惜暂时不能派上大用场了。

    续:valgrind的mips补丁,有空可以试一下:https://bugs.kde.org/show_bug.cgi?id=270777