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

  • 相关阅读:
    【leetcode】1365. How Many Numbers Are Smaller Than the Current Number
    【leetcode】1363. Largest Multiple of Three
    【leetcode】1362. Closest Divisors
    【leetcode】1361. Validate Binary Tree Nodes
    【leetcode】1360. Number of Days Between Two Dates
    【leetcode】1359. Count All Valid Pickup and Delivery Options
    【leetcode】1357. Apply Discount Every n Orders
    【leetcode】1356. Sort Integers by The Number of 1 Bits
    ISE应用入门的一些问题
    DDR的型号问题
  • 原文地址:https://www.cnblogs.com/freedomabcd/p/7771551.html
Copyright © 2011-2022 走看看