先来个感性认识吧:)
程序示例:test3.cpp
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 void f(void)
5 {
6 int *x =(int *) malloc(10*sizeof(int));
7 x[10] = 0;
8 }
9
10 int main()
11 {
12 f();
13 return 0;
14 }
编译链接该程序:
[root@p12 wangjia]# g++ -o test3 -ggdb test3.cpp
使用valgrind检查内存的调试信息:
[root@p12 wangjia]# valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./test3
==2866== Memcheck, a memory error detector.
==2866== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==2866== Using LibVEX rev 1606, a library for dynamic binary translation.
==2866== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==2866== Using valgrind-3.2.0, a dynamic binary instrumentation framework.
==2866== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==2866== For more details, rerun with: -v
==2866==
==2866== Invalid write of size 4
==2866== at 0x80483BF: f() (test3.cpp:7) //错误一:数组越界 + 错误位置
==2866== by 0x80483E8: main (test3.cpp:12)
==2866== Address 0x4252050 is 0 bytes after a block of size 40 alloc'd
==2866== at 0x401A6D6: malloc (vg_replace_malloc.c:149)
==2866== by 0x80483B5: f() (test3.cpp:6)
==2866== by 0x80483E8: main (test3.cpp:12)
==2866==
==2866== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 18 from 1)
==2866== malloc/free: in use at exit: 40 bytes in 1 blocks. //malloc 和 free 的使用情况
==2866== malloc/free: 1 allocs, 0 frees, 40 bytes allocated. //错误二:没有释放
==2866== For counts of detected errors, rerun with: -v
==2866== searching for pointers to 1 not-freed blocks.
==2866== checked 104,552 bytes.
==2866==
==2866==
==2866== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2866== at 0x401A6D6: malloc (vg_replace_malloc.c:149)
==2866== by 0x80483B5: f() (test3.cpp:6) //错误二所在位置
==2866== by 0x80483E8: main (test3.cpp:12)
==2866==
==2866== LEAK SUMMARY:
==2866== definitely lost: 40 bytes in 1 blocks.
==2866== possibly lost: 0 bytes in 0 blocks.
==2866== still reachable: 0 bytes in 0 blocks.
==2866== suppressed: 0 bytes in 0 blocks.
下面介绍下Valgrind:
Valgrind是 x86架构Linux上的多重用途代码剖析和内存调试工具。但它的主要功能还是对内存的调试,而且它的默认工具也是启动 memcheck。你可以在它的环境中运行你的程序来监视内存的使用情况,比如C 语言中的malloc和free或者 C++中的new和 delete。使用Valgrind的工具包,你可以自动的检测许多内存管理和线程的bug,避免花费太多的时间在bug寻找上,使得你的程序更加稳固。
一、Valgrind的主要功能(结合memcheck工具)
1,使用未初始化的内存 (Use of uninitialised memory)
2,使用已经释放了的内存 (Reading/writing memory after it has been free'd)
3,使用超过 malloc分配的内存空间(Reading/writing off the end of malloc'd blocks)
4,对堆栈的非法访问 (Reading/writing inappropriate areas on the stack)
5,申请的空间是否有释放 (Memory leaks -- where pointers to malloc'd blocks are lost forever)
6, malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
7, src和dst的重叠(Overlapping src and dst pointers in memcpy() and related functions)
二、Valgrind下载与安装
下载地址:http://download.chinaunix.net/download/0011000/10928.shtml
安装:
1)解压valgrind-3.2.0.tar.bz2
$bunzip2 valgrind-3.2.0.tar.bz2
$tar vfx valgrind-3.2.0.tar
2)解压后生成一个 valgrind-3.2.0目录
$cd valgrind-3.2.0
3)编译安装valgrind
$./configure
$make && make install
到这里valgrind就编译安装完成。
三、Valgrind使用参数
内存泄漏是最难发现的常 见错误之一,因为除非用完内存或调用 malloc 失 败,否则都不会导致任何问题。实际上,使用像 C 或 C++ 这类没有垃圾回收机制的语言时,你一大半的时间都花费在处理如何 正确释放内存上。如果程序运行时间足够长,一个小小的失误也会对程序造成重大的影响。
Valgrind 支持很多工具 :memcheck , addrcheck , cachegrind , massif , helgrind 和 callgrind 等。在运行 Valgrind 时,你必须指明想用的工具。如 $valgrind – tool=memcheck test ,将对 test 进行内存使用情况进行分析,包括 malloc/free/new/new[]/delete 。
如果没有其它参数, Valgrind 在程序结束后给出关于 free/delete 和 malloc/new 总 共调用次数的简报。
Valgrind 使用参数
--log-fd=N
默认情况下, 输出信息是到标准错误 stderr ,也可以 通过— log-fd=8 ,输出到描述符为 8 的文件
--log-file=filename 将输出的信息 写入到 filename.PID 的文件里, PID 是运行程序的进行 ID 。可以通过 --log-file-exactly=filename 指定就输出到 filename 文件。
--log-file-qualifier=, 取得环 境变量的值来做为输出信息的文件名。如 — log-file-qualifier=$FILENAME 。
--log-socket=IP:PORT
也 可以把输出信息发送到网络中指定的 IP:PORT 去
--error-limit=no
对 错误报告的个数据进行限制,默认情况不做限制
--tool= [default: memcheck]
--tool=memcheck :要求用 memcheck 这个工具对程序进行分析
--leak-ckeck=yes
要 求对 leak 给出详细信息
--leak-check=full 指的 是完全检查内存泄漏
--trace-children= [default: no]
跟踪到子进程里去,默认请况不跟踪
--xml= [default: no]
将 信息以 xml 格式输出,只有 memcheck 可用
--gen-suppressions= [default: no]
如果为 yes , valgrind 会在每发现一个错误便停下让用户做选择是继续还是 退出更多选项请参看: http://www.valgrind.org/docs/manual/manual-core.html 可以把一些默 认选项编辑在 ~/.valgrindrc 文 件里。
用 Valgrind 查找内存泄漏 , 我们必须带上这个参数:
--leak-check= [default: summary]
Leak 是指,存在一块没有被引用的内存空 间,或没有被释放的内存空间,如 summary , 只反馈一些总结信息,告诉你有多少个 malloc , 多少个 free 等;如果是 full 将输出所有的 leaks ,也就是定位到某一个 malloc/free 。
--show-reachable= [default: no]
如果为 no ,只输出没有引用的内存 leaks ,或指向 malloc 返回的内存块中部某处的 leaks
--undef-value-errors= [default: yes]
如果为 yes , memcheck 将对无定义值错进行检查
四、Valgrind要注意的问题
Valgrind 是 x86 架构上的工具,只能在 Linux 上运行 (FreeBSD 和 NetBSD 上的相关版本正在开发中 ) 。它允许程序员在它的环境里测试程序以检测未配对 malloc 调用 错误和其它使用非法内存 ( 未初始化内存 ) 的 错误以及非法内存操作 ( 比如同一块内存释放两次或调用不正确的析构函数 ) 。 Valgrind 不检查静态分配数组的使用情况。
五、错误分析(from other points——to be the references)
1.默认使用工具memcheck
2.输出到XML文件:valgrind --leak-check=full --xml=yes --log-file="log.xml" myprog arg1 arg2
3.错误解释
3.1Illegal read / Illegal write errors
例如:
Invalid read of size 4
at 0x40F6BBCC: (within /usr/lib/libpng.so.2.1.0.9)
by 0x40F6B804: (within /usr/lib/libpng.so.2.1.0.9)
by 0x40B07FF4: read_png_image(QImageIO *) (kernel/qpngio.cpp:326)
by 0x40AC751B: QImageIO::read() (kernel/qimage.cpp:3621)
Address 0xBFFFF0E0 is not stack'd, malloc'd or free'd
这个错误的发生是因为对一些memcheck猜想不应该访问的内存进行了读写。
3.2 Use of uninitialised values例如:
Conditional jump or move depends on uninitialised value (s)
at 0x402DFA94: _IO_vfprintf (_itoa.h:49)
by 0x402E8476: _IO_printf (printf.c:36)
by 0x8048472: main (tests/manuel1.c:8)
这 个错误的发生是因为使用了未初始化的数据。一般情况下有两种情形容易出现这个错误:
程序中的局部变量未初始化;
C语言malloc的内存 未初始化;C++中new的对象其成员未被初始化。
3.3 Illegal frees
例如:
Invalid free()
at 0x4004FFDF: free (vg_clientmalloc.c:577)
by 0x80484C7: main (tests/doublefree.c:10)
Address 0x3807F7B4 is 0 bytes inside a block of size 177 free'd
at 0x4004FFDF: free (vg_clientmalloc.c:577)
by 0x80484C7: main (tests/doublefree.c:10)
3.4 When a block is freed with an inappropriate deallocation function
例 如:
Mismatched free() / delete / delete []
at 0x40043249: free (vg_clientfuncs.c:171)
by 0x4102BB4E: QGArray::~QGArray(void) (tools/qgarray.cpp:149)
by 0x4C261C41: PptDoc::~PptDoc(void) (include/qmemarray.h:60)
by 0x4C261F0E: PptXml::~PptXml(void) (pptxml.cc:44)
Address 0x4BB292A8 is 0 bytes inside a block of size 64 alloc'd
at 0x4004318C: operator new[](unsigned int) (vg_clientfuncs.c:152)
by 0x4C21BC15: KLaola::readSBStream(int) const (klaola.cc:314)
by 0x4C21C155: KLaola::stream(KLaola::OLENode const *) (klaola.cc:416)
by 0x4C21788F: OLEFilter::convert(QCString const &) (olefilter.cc:272)
If allocated with malloc, calloc, realloc, valloc or memalign, you must deallocate with free.If allocated with new[], you must deallocate with delete[].If allocated with new, you must deallocate with delete.linux系统对上述错误可能不在意,但是移值到其他平台时却会有问题。
3.5 Passing system call parameters with inadequate read/write permissions
例如:
Syscall param write(buf) points to uninitialised byte(s)
at 0x25A48723: __write_nocancel (in /lib/tls/libc-2.3.3.so)
by 0x259AFAD3: __libc_start_main (in /lib/tls/libc-2.3.3.so)
by 0x8048348: (within /auto/homes/njn25/grind/head4/a.out)
Address 0x25AB8028 is 0 bytes inside a block of size 10 alloc'd
at 0x259852B0: malloc (vg_replace_malloc.c:130)
by 0x80483F1: main (a.c:5)
Syscall param exit(error_code) contains uninitialised byte(s)
at 0x25A21B44: __GI__exit (in /lib/tls/libc-2.3.3.so)
by 0x8048426: main (a.c:8)
Memcheck检查所有的被系统调用的参数。
It checks all the direct parameters themselves.
Also, if a system call needs to read from a buffer provided by your program, Memcheck checks that the entire buffer is addressable and has valid data, ie, it is readable.
Also, if the system call needs to write to a user-supplied buffer, Memcheck checks that the buffer is addressable.
例如:
#include <stdlib.h>
#include <unistd.h>
int main( void )
{
char* arr = malloc(10);
int* arr2 = malloc(sizeof(int));
write( 1 /* stdout */, arr, 10 );
exit(arr2[0]);
}
错误信息:
Syscall param write(buf) points to uninitialised byte(s)
at 0x25A48723: __write_nocancel (in /lib/tls/libc-2.3.3.so)
by 0x259AFAD3: __libc_start_main (in /lib/tls/libc-2.3.3.so)
by 0x8048348: (within /auto/homes/njn25/grind/head4/a.out)
Address 0x25AB8028 is 0 bytes inside a block of size 10 alloc'd
at 0x259852B0: malloc (vg_replace_malloc.c:130)
by 0x80483F1: main (a.c:5)
Syscall param exit(error_code) contains uninitialised byte(s)
at 0x25A21B44: __GI__exit (in /lib/tls/libc-2.3.3.so)
by 0x8048426: main (a.c:8)
传 递了无效参数到系统函数中。
3.6 Overlapping source and destination blocks
C的以下库函数拷贝数据从一块内存到另一块 内存时: memcpy(), strcpy(), strncpy(), strcat(), strncat(). 源和目的都不允许溢出。
例 如:
==27492== Source and destination overlap in memcpy(0xbffff294, 0xbffff280, 21)
==27492== at 0x40026CDC: memcpy (mc_replace_strmem.c:71)
==27492== by 0x804865A: main (overlap.c:40)
3.7 Memory leak detection
错误信息:
Still reachable: A pointer to the start of the block is found. This usually indicates programming sloppiness. Since the block is still pointed at, the programmer could, at least in principle, free it before program exit. Because these are very common and arguably not a problem, Memcheck won't report such blocks unless --show-reachable=yes is specified.
Possibly lost, or "dubious": A pointer to the interior of the block is found. The pointer might originally have pointed to the start and have been moved along, or it might be entirely unrelated. Memcheck deems such a block as "dubious", because it's unclear whether or not a pointer to it still exists.
Definitely lost, or "leaked": The worst outcome is that no pointer to the block can be found
[ps]:其中--leak-check=full 指的是完全检查内存泄漏,--show-reachable=yes是显示内存泄漏的地点,--trace-children=yes是跟入子进程。