Valgrind 例子

Posted 啃萝卜的兔子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Valgrind 例子相关的知识,希望对你有一定的参考价值。

检测内存泄漏

#include <stdlib.h>
#include <stdio.h>
int main(void)
{
       char *ptr;
       ptr = (char *)malloc(10);
       return 0;
}

保存为memleak.c并编译,然后用valgrind检测。

$ gcc -o memleak memleak.c

 

(valgrind和purify最大的不同在于:valgrind只接管程序执行的过程,编译时不需要valgrind干预,而purify会干预程序编译过程)

$ valgrind --tool=memcheck ./memleak

 

我们得到如下错误信息:

[konten@tencent test_valgrind]$ valgrind ./memleak
==29646== Memcheck, a memory error detector.
==29646== Copyright (C) 2002-2007, and GNU GPL\'d, by Julian Seward et al.
==29646== Using LibVEX rev 1732, a library for dynamic binary translation.
==29646== Copyright (C) 2004-2007, and GNU GPL\'d, by OpenWorks LLP.
==29646== Using valgrind-3.2.3, a dynamic binary instrumentation framework.
==29646== Copyright (C) 2000-2007, and GNU GPL\'d, by Julian Seward et al.
==29646== For more details, rerun with: -v
==29646==
==29646==
==29646== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 1)
==29646== malloc/free: in use at exit: 10 bytes in 1 blocks.   //指示在程序退出时,还有多少内存没有释放。
==29646== malloc/free: 1 allocs, 0 frees, 10 bytes allocated. // 指示该执行过程malloc和free调用的次数。
==29646== For counts of detected errors, rerun with: -v // 提示如果要更详细的信息,用-v选项。
==29646== searching for pointers to 1 not-freed blocks.
==29646== checked 56,164 bytes.
==29646==
==29646== LEAK SUMMARY:
==29646==    definitely lost: 10 bytes in 1 blocks.
==29646==      possibly lost: 0 bytes in 0 blocks.
==29646==    still reachable: 0 bytes in 0 blocks.
==29646==         suppressed: 0 bytes in 0 blocks.
==29646== Rerun with --leak-check=full to see details of leaked memory.
[konten@tencent test_valgrind]$

可以看到,如果我们仅仅用默认方式执行,valgrind只报告内存泄漏,但没有显示具体代码中泄漏的地方。

因此我们需要使用 “--leak-check=full”选项启动 valgrind,我们再执行一次:

[konten@tencent test_valgrind]$ valgrind --leak-check=full ./memleak
==29661== Memcheck, a memory error detector.
==29661== Copyright (C) 2002-2007, and GNU GPL\'d, by Julian Seward et al.
==29661== Using LibVEX rev 1732, a library for dynamic binary translation.
==29661== Copyright (C) 2004-2007, and GNU GPL\'d, by OpenWorks LLP.
==29661== Using valgrind-3.2.3, a dynamic binary instrumentation framework.
==29661== Copyright (C) 2000-2007, and GNU GPL\'d, by Julian Seward et al.
==29661== For more details, rerun with: -v
==29661==
==29661==
==29661== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 1)
==29661== malloc/free: in use at exit: 10 bytes in 1 blocks.
==29661== malloc/free: 1 allocs, 0 frees, 10 bytes allocated.
==29661== For counts of detected errors, rerun with: -v
==29661== searching for pointers to 1 not-freed blocks.
==29661== checked 56,164 bytes.
==29661==
==29661== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==29661==    at 0x401A846: malloc (vg_replace_malloc.c:149)
==29661==    by 0x804835D: main (memleak.c:6)
==29661==
==29661== LEAK SUMMARY:
==29661==    definitely lost: 10 bytes in 1 blocks.
==29661==      possibly lost: 0 bytes in 0 blocks.
==29661==    still reachable: 0 bytes in 0 blocks.
==29661==         suppressed: 0 bytes in 0 blocks.
[konten@tencent test_valgrind]$

和上次的执行结果基本相同,只是指明了代码中出现泄漏的具体位置。

 

#include <stdlib.h>
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.

 

使用未初始化的内存

#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.

内存读写越界

#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.

src和dst内存覆盖

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
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.

 

 

动态内存管理错误

常见的内存分配方式分三种:静态存储,栈上分配,堆上分配。全局变量属于静态存储,它们是在编译时就被分配了存储空间,函数内的局部变量属于栈上分配,而最灵活的内存使用方式当属堆上分配,也叫做内存动态分配了。常用的内存动态分配函数包括:malloc, alloc, realloc, new等,动态释放函数包括free, delete。

一旦成功申请了动态内存,我们就需要自己对其进行内存管理,而这又是最容易犯错误的。常见的内存动态管理错误包括:

1. 申请和释放不一致

由于 C++ 兼容 C,而 C 与 C++ 的内存申请和释放函数是不同的,因此在 C++ 程序中,就有两套动态内存管理函数。一条不变的规则就是采用 C 方式申请的内存就用 C 方式释放;用 C++ 方式申请的内存,用 C++ 方式释放。也就是用 malloc/alloc/realloc 方式申请的内存,用 free 释放;用 new 方式申请的内存用 delete 释放。在上述程序中,用 malloc 方式申请了内存却用 delete 来释放,虽然这在很多情况下不会有问题,但这绝对是潜在的问题。

2. 申请和释放不匹配

申请了多少内存,在使用完成后就要释放多少。如果没有释放,或者少释放了就是内存泄露;多释放了也会产生问题。上述程序中,指针p和pt指向的是同一块内存,却被先后释放两次。

3.释放后仍然读写

本质上说,系统会在堆上维护一个动态内存链表,如果被释放,就意味着该块内存可以继续被分配给其他部分,如果内存被释放后再访问,就可能覆盖其他部分的信息,这是一种严重的错误,上述程序第16行中就在释放后仍然写这块内存。

下面的一段程序,就包括了内存动态管理中常见的错误。

#include <stdlib.h>
#include <stdio.h>
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.

 

非法写/读

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.

 

无效指针

#include <stdlib.h>
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.

 

重复释放

 

#include <stdlib.h>
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.

 

综合

  我们下面的例子中包括常见的几类内存问题:堆中的内存越界、踩内存、栈中的内存越界、非法指针。

#include <stdlib.h>
#include <stdio.h>
int main(void)
{
    char *ptr = malloc(10);
    ptr[12] = \'a\'; // 内存越界
    memcpy(ptr +1, ptr, 5); // 踩内存
    char a[10];
    a[12] = \'i\'; // 数组越界
     free(ptr); // 重复释放
       free(ptr);
    char *p1;
    *p1 = \'1\'; // 非法指针
   
    return 0;
}
编译: gcc -o invalidptr invalidptr.c -g
执行:valgrind --leak-check=full ./invalidptr
结果如下:
[konten@tencent test_valgrind]$ valgrind --leak-check=full ./invalidptr
==29776== Memcheck, a memory error detector.
==29776== Copyright (C) 2002-2007, and GNU GPL\'d, by Julian Seward et al.
==29776== Using LibVEX rev 1732, a library for dynamic binary translation.
==29776== Copyright (C) 2004-2007, and GNU GPL\'d, by OpenWorks LLP.
==29776== Using valgrind-3.2.3, a dynamic binary instrumentation framework.
==29776== Copyright (C) 2000-2007, and GNU GPL\'d, by Julian Seward et al.
==29776== For more details, rerun with: -v
==29776==
==29776== Invalid write of size 1 //堆内存越界被查出来
==29776==    at 0x80483D2: main (invalidptr.c:7)
==29776== Address 0x4159034 is 2 bytes after a block of size 10 alloc\'d
==29776==    at 0x401A846: 分享几个实用的代码片段(附代码例子)

分享几个实用的代码片段(附代码例子)

valgrind 代码检查,内存泄漏

性能分析之valgrind及相关工具

如何创建片段以重复变量编号中的代码行

为啥这段代码在 valgrind (helgrind) 下失败?