内存动态分析工具Valgrind初探

    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 redirection
valgrind:  which is mandatory for this platform-tool combination
valgrind:  cannot be set up.  Details of the redirection are:
valgrind:
valgrind:  A must-be-redirected function
valgrind:  whose name matches the pattern:      strlen
valgrind:  in an object with soname matching:   ld-linux-x86-64.so.2
valgrind:  was not found whilst processing
valgrind:  symbols from the object with soname: ld-linux-x86-64.so.2
valgrind:
valgrind:  Possible fixes: (1, short term): install glibc's debuginfo
valgrind:  package on this machine.  (2, longer term): ask the packagers
valgrind:  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 standard
valgrind:  calling conventions for this platform.  The package you need
valgrind:  to install for fix (1) is called
valgrind:
valgrind:    On Debian, Ubuntu:                 libc6-dbg
valgrind:    On SuSE, openSuSE, Fedora, RHEL:   glibc-debuginfo
valgrind:
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 108
drwxr-xr-x   2 root root  4096 2012-07-13 03:26 bin
drwxr-xr-x   3 root root  4096 2012-07-13 07:36 boot
drwxr-xr-x   2 root root  4096 2012-07-13 07:06 cdrom
drwxr-xr-x  17 root root  3620 2012-07-24 03:00 dev
drwxr-xr-x 128 root root 12288 2012-07-24 03:06 etc
drwxr-xr-x   3 root root  4096 2012-07-13 08:16 home
lrwxrwxrwx   1 root root    33 2012-07-13 07:07 initrd.img -> boot/initrd.img-2.6.32-38-generic
drwxr-xr-x  16 root root 12288 2012-07-13 03:23 lib
drwxr-xr-x   2 root root  4096 2012-07-13 03:24 lib32
lrwxrwxrwx   1 root root     4 2012-07-13 07:03 lib64 -> /lib
drwx------   2 root root 16384 2012-07-13 07:03 lost+found
drwxr-xr-x   4 root root  4096 2012-07-13 02:13 media
drwxr-xr-x   2 root root  4096 2012-02-03 04:21 mnt
drwxr-xr-x   2 root root  4096 2012-07-13 07:03 opt
dr-xr-xr-x 182 root root     0 2012-07-24 02:58 proc
drwx------   8 root root  4096 2012-07-24 21:25 root
drwxr-xr-x   2 root root  4096 2012-07-16 01:21 sbin
drwxr-xr-x   2 root root  4096 2009-12-05 17:25 selinux
drwxr-xr-x   2 root root  4096 2012-07-13 07:03 srv
drwxr-xr-x  13 root root     0 2012-07-24 02:58 sys
drwxrwxrwx   2 root root  4096 2012-07-16 01:39 tftpboot
drwxrwxrwt  14 root root  4096 2012-07-24 21:31 tmp
drwxr-xr-x  11 root root  4096 2012-07-13 03:23 usr
drwxr-xr-x  15 root root  4096 2012-07-13 07:31 var
lrwxrwxrwx   1 root root    30 2012-07-13 07:07 vmlinuz -> boot/vmlinuz-2.6.32-38-generic
drwxrwxrwx   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 
/* 
 * ===  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


你可能感兴趣的:(内存管理)