Valgrind是一款用于内存调试、内存泄漏检测以及性能分析的软件开发工具。
今天经同事介绍,发现了有这么一款工具,可以在linux中检测程序中存在的内存泄露情况。
使用方法: valgrind -v --tool=memcheck --leak-check=full ./processname
之后,就会运行程序,然后Valgrind就会在可能或者肯定有内存操作问题的地方输出错误提示。
下面有关一些Valgrind的一些错误提示及提示所表明的错误操作情况的简单举例。
原文地址:http://www.cnblogs.com/wangkangluo1/archive/2011/07/20/2111273.html
例1.使用未初始化的内存
代码如下
#include <stdio.h>
int main()
{
int x;
if(x == 0)
{
printf("X is zero");
}
return 0;
}
Valgrind提示如下
==14222== Conditional jump or move depends on uninitialised value(s)
==14222== at 0x400484: main (sample2.c:6)
X is zero==14222==
==14222== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==14222== malloc/free: in use at exit: 0 bytes in 0 blocks.
==14222== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==14222== For counts of detected errors, rerun with: -v
==14222== All heap blocks were freed -- no leaks are possible.
例2.内存读写越界
代码如下
#include <stdlib.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
int len=5;
int i;
int *pt=(int*)malloc(len*sizeof(int));
int *p=pt;
for(i=0;i<len;i++)
{p++;}
*p=5;
printf(“%d”,*p);
return;
}
Valgrind提示如下
==23045== Invalid write of size 4
==23045== at 0x40050A: main (sample2.c:11)
==23045== Address 0x4C2E044 is 0 bytes after a block of size 20 alloc'd
==23045== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==23045== by 0x4004DF: main (sample2.c:7)
==23045==
==23045== Invalid read of size 4
==23045== at 0x400514: main (sample2.c:12)
==23045== Address 0x4C2E044 is 0 bytes after a block of size 20 alloc'd
==23045== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==23045== by 0x4004DF: main (sample2.c:7)
5==23045==
==23045== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 5 from 1)
==23045== malloc/free: in use at exit: 20 bytes in 1 blocks.
==23045== malloc/free: 1 allocs, 0 frees, 20 bytes allocated.
==23045== For counts of detected errors, rerun with: -v
==23045== searching for pointers to 1 not-freed blocks.
==23045== checked 66,584 bytes.
==23045==
==23045== LEAK SUMMARY:
==23045== definitely lost: 20 bytes in 1 blocks.
==23045== possibly lost: 0 bytes in 0 blocks.
==23045== still reachable: 0 bytes in 0 blocks.
==23045== suppressed: 0 bytes in 0 blocks.
==23045== Use --leak-check=full to see details of leaked memory.
例3.src和dst内存覆盖
代码如下
#include
#include
#include
int main(int argc,char *argv[])
{ char x[50];
int i;
for(i=0;i<50;i++)
{x[i]=i;}
strncpy(x+20,x,20); //Good
strncpy(x+20,x,21); //Overlap
x[39]=’\0’;
strcpy(x,x+20); //Good
x[39]=40;
x[40]=’\0’;
strcpy(x,x+20); //Overlap
return 0;
}
Valgrind提示如下
==24139== Source and destination overlap in strncpy(0x7FEFFFC09, 0x7FEFFFBF5, 21)
==24139== at 0x4A0724F: strncpy (mc_replace_strmem.c:116)
==24139== by 0x400527: main (sample3.c:10)
==24139==
==24139== Source and destination overlap in strcpy(0x7FEFFFBE0, 0x7FEFFFBF4)
==24139== at 0x4A06E47: strcpy (mc_replace_strmem.c:106)
==24139== by 0x400555: main (sample3.c:15)
==24139==
==24139== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 5 from 1)
==24139== malloc/free: in use at exit: 0 bytes in 0 blocks.
==24139== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==24139== For counts of detected errors, rerun with: -v
==24139== All heap blocks were freed -- no leaks are possible.
例4.动态内存管理错误
常见的内存分配方式分三种:静态存储,栈上分配,堆上分配。全局变量属于静态存储,它们是在编译时就被分配了存储空间,函数内的局部变量属于栈上分配,而最灵活的内存使用方式当属堆上分配,也叫做内存动态分配了。常用的内存动态分配函数包括:malloc, alloc, realloc, new等,动态释放函数包括free, delete。
一旦成功申请了动态内存,我们就需要自己对其进行内存管理,而这又是最容易犯错误的。常见的内存动态管理错误包括:
l 申请和释放不一致
由于 C++ 兼容 C,而 C 与 C++ 的内存申请和释放函数是不同的,因此在 C++ 程序中,就有两套动态内存管理函数。一条不变的规则就是采用 C 方式申请的内存就用 C 方式释放;用 C++ 方式申请的内存,用 C++ 方式释放。也就是用 malloc/alloc/realloc 方式申请的内存,用 free 释放;用 new 方式申请的内存用 delete 释放。在上述程序中,用 malloc 方式申请了内存却用 delete 来释放,虽然这在很多情况下不会有问题,但这绝对是潜在的问题。
l 申请和释放不匹配
申请了多少内存,在使用完成后就要释放多少。如果没有释放,或者少释放了就是内存泄露;多释放了也会产生问题。上述程序中,指针p和pt指向的是同一块内存,却被先后释放两次。
l 释放后仍然读写
本质上说,系统会在堆上维护一个动态内存链表,如果被释放,就意味着该块内存可以继续被分配给其他部分,如果内存被释放后再访问,就可能覆盖其他部分的信息,这是一种严重的错误,上述程序第16行中就在释放后仍然写这块内存。
下面的一段程序,就包括了内存动态管理中常见的错误。
#include
#include
int main(int argc,char *argv[])
{ char *p=(char*)malloc(10);
char *pt=p;
int i;
for(i=0;i<10;i++)
{p[i]=’z’;}
delete p;
p[1]=’a’;
free(pt);
return 0;
}
Valgrind提示如下
==25811== Mismatched free() / delete / delete []
==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==25811== by 0x400654: main (sample4.c:9)
==25811== Address 0x4C2F030 is 0 bytes inside a block of size 10 alloc'd
==25811== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==25811== by 0x400620: main (sample4.c:4)
==25811==
==25811== Invalid write of size 1
==25811== at 0x40065D: main (sample4.c:10)
==25811== Address 0x4C2F031 is 1 bytes inside a block of size 10 free'd
==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==25811== by 0x400654: main (sample4.c:9)
==25811==
==25811== Invalid free() / delete / delete[]
==25811== at 0x4A0541E: free (vg_replace_malloc.c:233)
==25811== by 0x400668: main (sample4.c:11)
==25811== Address 0x4C2F030 is 0 bytes inside a block of size 10 free'd
==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==25811== by 0x400654: main (sample4.c:9)
==25811==
==25811== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 5 from 1)
==25811== malloc/free: in use at exit: 0 bytes in 0 blocks.
==25811== malloc/free: 1 allocs, 2 frees, 10 bytes allocated.
==25811== For counts of detected errors, rerun with: -v
==25811== All heap blocks were freed -- no leaks are possible.
例5.内存泄漏
代码如下
#include
int main()
{
char *x = (char*)malloc(20);
char *y = (char*)malloc(20);
x=y;
free(x);
free(y);
return 0;
}
Valgrind提示如下
==19013== Invalid free() / delete / delete[]
==19013== at 0x4A0541E: free (vg_replace_malloc.c:233)
==19013== by 0x4004F5: main (sample5.c:8)
==19013== Address 0x4C2E078 is 0 bytes inside a block of size 20 free'd
==19013== at 0x4A0541E: free (vg_replace_malloc.c:233)
==19013== by 0x4004EC: main (sample5.c:7)
==19013==
==19013== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==19013== malloc/free: in use at exit: 20 bytes in 1 blocks.
==19013== malloc/free: 2 allocs, 2 frees, 40 bytes allocated.
==19013== For counts of detected errors, rerun with: -v
==19013== searching for pointers to 1 not-freed blocks.
==19013== checked 66,584 bytes.
==19013==
==19013== LEAK SUMMARY:
==19013== definitely lost: 20 bytes in 1 blocks.
==19013== possibly lost: 0 bytes in 0 blocks.
==19013== still reachable: 0 bytes in 0 blocks.
==19013== suppressed: 0 bytes in 0 blocks.
==19013== Use --leak-check=full to see details of leaked memory.
例6.非法写/读
代码如下
int main()
{
int i, *x;
x = (int *)malloc(10*sizeof(int));
for (i=0; i<11; i++)
x[i] = i;
free(x);
}
Valgrind提示如下
==21483== Invalid write of size 4
==21483== at 0x4004EA: main (sample6.c:6)
==21483== Address 0x4C2E058 is 0 bytes after a block of size 40 alloc'd
==21483== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==21483== by 0x4004C9: main (sample6.c:4)
==21483==
==21483== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==21483== malloc/free: in use at exit: 0 bytes in 0 blocks.
==21483== malloc/free: 1 allocs, 1 frees, 40 bytes allocated.
==21483== For counts of detected errors, rerun with: -v
==21483== All heap blocks were freed -- no leaks are possible.
例7.无效指针
代码如下
#include
int main()
{
char *x = malloc(10);
x[10] = 'a';
free(x);
return 0;
}
Valgrind提示如下
==15262== Invalid write of size 1
==15262== at 0x4004D6: main (sample7.c:5)
==15262== Address 0x4C2E03A is 0 bytes after a block of size 10 alloc'd
==15262== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==15262== by 0x4004C9: main (sample7.c:4)
==15262==
==15262== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==15262== malloc/free: in use at exit: 0 bytes in 0 blocks.
==15262== malloc/free: 1 allocs, 1 frees, 10 bytes allocated.
==15262== For counts of detected errors, rerun with: -v
==15262== All heap blocks were freed -- no leaks are possible.
例8.重复释放
代码如下
#include
int main()
{
char *x = malloc(10);
free(x);
free(x);
return 0;
}
Valgrind提示如下
==15005== Invalid free() / delete / delete[]
==15005== at 0x4A0541E: free (vg_replace_malloc.c:233)
==15005== by 0x4004DF: main (sample8.c:6)
==15005== Address 0x4C2E030 is 0 bytes inside a block of size 10 free'd
==15005== at 0x4A0541E: free (vg_replace_malloc.c:233)
==15005== by 0x4004D6: main (sample8.c:5)
==15005==
==15005== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==15005== malloc/free: in use at exit: 0 bytes in 0 blocks.
==15005== malloc/free: 1 allocs, 2 frees, 10 bytes allocated.
==15005== For counts of detected errors, rerun with: -v
==15005== All heap blocks were freed -- no leaks are possible.
Valgrind的局限
l Valgrind不对静态数组(分配在栈上)进行边界检查。如果在程序中声明了一个数组:
int main()
{
char x[10];
x[11] = 'a';
}
Valgrind则不会警告你,你可以把数组改为动态在堆上分配的数组,这样就可能进行边界检查了。这个方法好像有点得不偿失的感觉。
l Valgrind占用了更多的内存--可达两倍于你程序的正常使用量。如果你用Valgrind来检测使用大量内存的程序就会遇到问题,它可能会用很长的时间来运行测试。大多数情况下,这都不是问题,即使速度慢也仅是检测时速度慢,如果你用Valgrind来检测一个正常运行时速度就很慢的程序,这下问题就大了。 Valgrind不可能检测出你在程序中犯下的所有错误--如果你不检查缓冲区溢出,Valgrind也不会告诉你代码写了它不应该写的内存。