zoukankan      html  css  js  c++  java
  • 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: malloc (vg_replace_malloc.c:149)
    ==29776==    by 0x80483C5: main (invalidptr.c:6)
    ==29776==
    ==29776== Source and destination overlap in memcpy(0x4159029, 0x4159028, 5) //踩内存
    ==29776==    at 0x401C96D: memcpy (mc_replace_strmem.c:116)
    ==29776==    by 0x80483E6: main (invalidptr.c:9)
    ==29776==
    ==29776== Invalid free() / delete / delete[] //重复释放
    ==29776==    at 0x401B3FB: free (vg_replace_malloc.c:233)
    ==29776==    by 0x8048406: main (invalidptr.c:16)
    ==29776== Address 0x4159028 is 0 bytes inside a block of size 10 free'd
    ==29776==    at 0x401B3FB: free (vg_replace_malloc.c:233)
    ==29776==    by 0x80483F8: main (invalidptr.c:15)
    ==29776==
    ==29776== Use of uninitialised value of size 4
    ==29776==    at 0x804840D: main (invalidptr.c:19)
    ==29776== //非法指针,导致coredump
    ==29776== Process terminating with default action of signal 11 (SIGSEGV): dumping core
    ==29776== Bad permissions for mapped region at address 0x80482AD
    ==29776==    at 0x804840D: main (invalidptr.c:19)
    ==29776==
    ==29776== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 15 from 1)
    ==29776== malloc/free: in use at exit: 0 bytes in 0 blocks.
    ==29776== malloc/free: 1 allocs, 2 frees, 10 bytes allocated.
    ==29776== For counts of detected errors, rerun with: -v
    ==29776== All heap blocks were freed -- no leaks are possible.
    Segmentation fault
    [konten@tencent test_valgrind]$

    从上面的结果看出,除了栈内存越界外,其他常见的内存问题都可以用valgrind简单的查出来。

    参考

    http://www.cnblogs.com/wangkangluo1/archive/2011/07/20/2111248.html

    http://www.cnblogs.com/wangkangluo1/archive/2011/07/20/2111273.html

  • 相关阅读:
    Lumen源码分析之 一步一步带你实现Lumen容器(一)
    php 注册器模式 工厂模式
    理解 PHP 依赖注入 和 控制反转
    composer使用git作为仓储
    monolog记录日志
    Jupyter Notebook快捷键
    图像灰度化
    一道算法题:拼数字
    [转]Vue生态系统中的库
    window.postMessage实现网页间通信
  • 原文地址:https://www.cnblogs.com/freedomabcd/p/7771551.html
Copyright © 2011-2022 走看看