Chinaunix首页 | 论坛 | 博客
  • 博客访问: 18389
  • 博文数量: 6
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-01 10:36
文章分类
文章存档

2013年(6)

我的朋友

分类: C/C++

2013-04-25 00:12:59

  一,memcheck 功能概述
        valgrind包含很多工具,其中memcheck是一个内存错误检测工具。它能检测出C/C++中的常见内存问题:
      (1)内存访问错误,如内存溢出,访问已释放的内存;
      (2)使用未初始化的值;
      (3)不正确的释放内存,如两次释放内存块,或者不匹配的使用malloc/new/new[] ,  对应于 free/delete/delete[];
        (4)   使用memcoy相关函数导致的内存重叠 ;
      (5)内存泄漏;   


二,使用示例
        (1)非法读/写错误
code:

点击(此处)折叠或打开

  1. int main()
  2. {
  3.         int* __array = new int[10];
  4.         // use __array and delete it
  5.         if(__array)
  6.         {
  7.                 // ...
  8.                 // use delete but not delete []
  9.                 delete __array;
  10.         }
  11.         // use __array again
  12.         int __val = __array[0];
  13.         __array[0] = 0;
  14.         return 0;
  15. }
usage:

点击(此处)折叠或打开

  1. valgrind --tool=memcheck --read-var-info=yes --log-file=memcheck.log ./illegal_r_w_test
output:

点击(此处)折叠或打开

  1. ==24579== Memcheck, a memory error detector
  2. ==24579== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
  3. ==24579== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
  4. ==24579== Command: ./illegal_r_w_test
  5. ==24579== Parent PID: 19990
  6. ==24579==
  7. ==24579== Mismatched free() / delete / delete []
  8. ==24579== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
  9. ==24579== by 0x40062C: main (illegal_r_w_test.cc:9)
  10. ==24579== Address 0x4c37040 is 0 bytes inside a block of size 40 alloc'd
  11. ==24579== at 0x4A07062: operator new[](unsigned long) (vg_replace_malloc.c:363)
  12. ==24579== by 0x400615: main (illegal_r_w_test.cc:3)
  13. ==24579==
  14. ==24579== Invalid read of size 4
  15. ==24579== at 0x400631: main (illegal_r_w_test.cc:12)
  16. ==24579== Address 0x4c37040 is 0 bytes inside a block of size 40 free'd
  17. ==24579== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
  18. ==24579== by 0x40062C: main (illegal_r_w_test.cc:9)
  19. ==24579==
  20. ==24579== Invalid write of size 4
  21. ==24579== at 0x40063A: main (illegal_r_w_test.cc:13)
  22. ==24579== Address 0x4c37040 is 0 bytes inside a block of size 40 free'd
  23. ==24579== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
  24. ==24579== by 0x40062C: main (illegal_r_w_test.cc:9)
  25. ==24579==
  26. ==24579==
  27. ==24579== HEAP SUMMARY:
  28. ==24579== in use at exit: 0 bytes in 0 blocks
  29. ==24579== total heap usage: 1 allocs, 1 frees, 40 bytes allocated
  30. ==24579==
  31. ==24579== All heap blocks were freed -- no leaks are possible
  32. ==24579==
  33. ==24579== For counts of detected and suppressed errors, rerun with: -v
  34. ==24579== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 4 from 4)
anysis:
        输出结果中,14~18行,Invalid read of size 4,检测到了内存读错误,定位到代码illegal_r_w_test.cc:12,试图读一个已经释放的内存地址;
        20~24行,Invalid write of size 4,检测到了内存写错误,定位到代码illegal_r_w_test.cc:13,试图写一个已经释放的内存地址;
        7~12行,Mismatched free() / delete / delete [],不匹配的使用new delete[],代码定位illegal_r_w_test.cc:9;
        使用--read-var-info选项能获取更多的信息,但可能会使程序运行更慢。


        (2) 使用未初始化的内存
code:

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. int main()
  3. {
  4.         bool __init = false;
  5.         int __a;
  6.         int __b;
  7.         int* __c = new int;
  8.         if(__init)
  9.         {
  10.                 __a = 0;
  11.         }
  12.         printf("value __a = %d\n",__a);
  13.         printf("value __b = %d\n",__b);
  14.         printf("value __c = %d\n",*__c);
  15.         return 0;
  16. }
usage:

点击(此处)折叠或打开

  1. valgrind --tool=memcheck --track-origins=yes --log-file=memcheck.log ./uninitialised_val_test
output:

点击(此处)折叠或打开

  1. ==30131== Memcheck, a memory error detector
  2. ==30131== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
  3. ==30131== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
  4. ==30131== Command: ./uninitialised_val_test
  5. ==30131== Parent PID: 19990
  6. ==30131==
  7. ==30131== Use of uninitialised value of size 8
  8. ==30131== at 0x3FABC437DB: _itoa_word (in /lib64/libc-2.12.so)
  9. ==30131== by 0x3FABC46397: vfprintf (in /lib64/libc-2.12.so)
  10. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  11. ==30131== by 0x40063E: main (uninitialised_val_test.cc:12)
  12. ==30131== Uninitialised value was created by a stack allocation
  13. ==30131== at 0x400604: main (uninitialised_val_test.cc:3)
  14. ==30131==
  15. ==30131== Conditional jump or move depends on uninitialised value(s)
  16. ==30131== at 0x3FABC437E5: _itoa_word (in /lib64/libc-2.12.so)
  17. ==30131== by 0x3FABC46397: vfprintf (in /lib64/libc-2.12.so)
  18. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  19. ==30131== by 0x40063E: main (uninitialised_val_test.cc:12)
  20. ==30131== Uninitialised value was created by a stack allocation
  21. ==30131== at 0x400604: main (uninitialised_val_test.cc:3)
  22. ==30131==
  23. ==30131== Conditional jump or move depends on uninitialised value(s)
  24. ==30131== at 0x3FABC459A9: vfprintf (in /lib64/libc-2.12.so)
  25. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  26. ==30131== by 0x40063E: main (uninitialised_val_test.cc:12)
  27. ==30131== Uninitialised value was created by a stack allocation
  28. ==30131== at 0x400604: main (uninitialised_val_test.cc:3)
  29. ==30131==
  30. ==30131== Conditional jump or move depends on uninitialised value(s)
  31. ==30131== at 0x3FABC459C7: vfprintf (in /lib64/libc-2.12.so)
  32. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  33. ==30131== by 0x40063E: main (uninitialised_val_test.cc:12)
  34. ==30131== Uninitialised value was created by a stack allocation
  35. ==30131== at 0x400604: main (uninitialised_val_test.cc:3)
  36. ==30131==
  37. ==30131== Use of uninitialised value of size 8
  38. ==30131== at 0x3FABC437DB: _itoa_word (in /lib64/libc-2.12.so)
  39. ==30131== by 0x3FABC46397: vfprintf (in /lib64/libc-2.12.so)
  40. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  41. ==30131== by 0x400652: main (uninitialised_val_test.cc:13)
  42. ==30131== Uninitialised value was created by a stack allocation
  43. ==30131== at 0x400604: main (uninitialised_val_test.cc:3)
  44. ==30131==
  45. ==30131== Conditional jump or move depends on uninitialised value(s)
  46. ==30131== at 0x3FABC437E5: _itoa_word (in /lib64/libc-2.12.so)
  47. ==30131== by 0x3FABC46397: vfprintf (in /lib64/libc-2.12.so)
  48. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  49. ==30131== by 0x400652: main (uninitialised_val_test.cc:13)
  50. ==30131== Uninitialised value was created by a stack allocation
  51. ==30131== at 0x400604: main (uninitialised_val_test.cc:3)
  52. ==30131==
  53. ==30131== Conditional jump or move depends on uninitialised value(s)
  54. ==30131== at 0x3FABC459A9: vfprintf (in /lib64/libc-2.12.so)
  55. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  56. ==30131== by 0x400652: main (uninitialised_val_test.cc:13)
  57. ==30131== Uninitialised value was created by a stack allocation
  58. ==30131== at 0x400604: main (uninitialised_val_test.cc:3)
  59. ==30131==
  60. ==30131== Conditional jump or move depends on uninitialised value(s)
  61. ==30131== at 0x3FABC459C7: vfprintf (in /lib64/libc-2.12.so)
  62. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  63. ==30131== by 0x400652: main (uninitialised_val_test.cc:13)
  64. ==30131== Uninitialised value was created by a stack allocation
  65. ==30131== at 0x400604: main (uninitialised_val_test.cc:3)
  66. ==30131==
  67. ==30131== Use of uninitialised value of size 8
  68. ==30131== at 0x3FABC437DB: _itoa_word (in /lib64/libc-2.12.so)
  69. ==30131== by 0x3FABC46397: vfprintf (in /lib64/libc-2.12.so)
  70. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  71. ==30131== by 0x400669: main (uninitialised_val_test.cc:14)
  72. ==30131== Uninitialised value was created by a heap allocation
  73. ==30131== at 0x4A074CC: operator new(unsigned long) (vg_replace_malloc.c:298)
  74. ==30131== by 0x400619: main (uninitialised_val_test.cc:7)
  75. ==30131==
  76. ==30131== Conditional jump or move depends on uninitialised value(s)
  77. ==30131== at 0x3FABC437E5: _itoa_word (in /lib64/libc-2.12.so)
  78. ==30131== by 0x3FABC46397: vfprintf (in /lib64/libc-2.12.so)
  79. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  80. ==30131== by 0x400669: main (uninitialised_val_test.cc:14)
  81. ==30131== Uninitialised value was created by a heap allocation
  82. ==30131== at 0x4A074CC: operator new(unsigned long) (vg_replace_malloc.c:298)
  83. ==30131== by 0x400619: main (uninitialised_val_test.cc:7)
  84. ==30131==
  85. ==30131== Conditional jump or move depends on uninitialised value(s)
  86. ==30131== at 0x3FABC459A9: vfprintf (in /lib64/libc-2.12.so)
  87. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  88. ==30131== by 0x400669: main (uninitialised_val_test.cc:14)
  89. ==30131== Uninitialised value was created by a heap allocation
  90. ==30131== at 0x4A074CC: operator new(unsigned long) (vg_replace_malloc.c:298)
  91. ==30131== by 0x400619: main (uninitialised_val_test.cc:7)
  92. ==30131==
  93. ==30131== Conditional jump or move depends on uninitialised value(s)
  94. ==30131== at 0x3FABC459C7: vfprintf (in /lib64/libc-2.12.so)
  95. ==30131== by 0x3FABC4EAC9: printf (in /lib64/libc-2.12.so)
  96. ==30131== by 0x400669: main (uninitialised_val_test.cc:14)
  97. ==30131== Uninitialised value was created by a heap allocation
  98. ==30131== at 0x4A074CC: operator new(unsigned long) (vg_replace_malloc.c:298)
  99. ==30131== by 0x400619: main (uninitialised_val_test.cc:7)
  100. ==30131==
  101. ==30131==
  102. ==30131== HEAP SUMMARY:
  103. ==30131== in use at exit: 4 bytes in 1 blocks
  104. ==30131== total heap usage: 1 allocs, 0 frees, 4 bytes allocated
  105. ==30131==
  106. ==30131== LEAK SUMMARY:
  107. ==30131== definitely lost: 4 bytes in 1 blocks
  108. ==30131== indirectly lost: 0 bytes in 0 blocks
  109. ==30131== possibly lost: 0 bytes in 0 blocks
  110. ==30131== still reachable: 0 bytes in 0 blocks
  111. ==30131== suppressed: 0 bytes in 0 blocks
  112. ==30131== Rerun with --leak-check=full to see details of leaked memory
  113. ==30131==
  114. ==30131== For counts of detected and suppressed errors, rerun with: -v
  115. ==30131== ERROR SUMMARY: 26 errors from 12 contexts (suppressed: 4 from 4)
anysis:
        7~12行,Use of uninitialised value of size 8,使用了未初始化的变量,代码定位uninitialised_val_test.cc:12;Uninitialised value was created by a stack allocation,变量是在栈上分配的,局部变量声明在uninitialised_val_test.cc:3处;
        15~21,Conditional jump or move depends on uninitialised value(s),此处说明条件跳过变量初始化,如果条件不成立情况下,可能会导致使用未初始化道值;
        67~74 ,Use of uninitialised value of size 8, 使用了未初始化的变量,Uninitialised value was created by a heap allocation,变量在堆上分配的;
        107 行同时检测到内存泄漏,变量__c动态申请空间后没有释放;
        --track-origins=yes 选项能更容易的跟踪获取未初始化值错误;Uninitialised value was created by a heap allocation既是加入这个选项给出的额外信息;


        (3)系统调用中使用未初始化或者不可寻址的值
code:

点击(此处)折叠或打开

  1. #include<unistd.h>
  2. #include<stdlib.h>
  3. int main()
  4. {
  5.         char* __arr1 = (char*)malloc(10);
  6.         int* __arr2 = (int*)malloc(sizeof(int));
  7.         write(1,__arr1,10);
  8.         exit(__arr2[0]);
  9. }
usage:

点击(此处)折叠或打开

  1. valgrind --tool=memcheck --track-origins=yes --log-file=memcheck.log ./unaddressbale_test
output:

点击(此处)折叠或打开

  1. ==3615== Memcheck, a memory error detector
  2. ==3615== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
  3. ==3615== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
  4. ==3615== Command: ./unaddressbale_test
  5. ==3615== Parent PID: 30468
  6. ==3615==
  7. ==3615== Syscall param write(buf) points to uninitialised byte(s)
  8. ==3615== at 0x3FABCDA3C0: __write_nocancel (in /lib64/libc-2.12.so)
  9. ==3615== by 0x40066D: main (unaddressbale_test.cc:7)
  10. ==3615== Address 0x4c37040 is 0 bytes inside a block of size 10 alloc'd
  11. ==3615== at 0x4A068FE: malloc (vg_replace_malloc.c:270)
  12. ==3615== by 0x400645: main (unaddressbale_test.cc:5)
  13. ==3615== Uninitialised value was created by a heap allocation
  14. ==3615== at 0x4A068FE: malloc (vg_replace_malloc.c:270)
  15. ==3615== by 0x400645: main (unaddressbale_test.cc:5)
  16. ==3615==
  17. ==3615== Syscall param exit_group(status) contains uninitialised byte(s)
  18. ==3615== at 0x3FABCABC68: _Exit (in /lib64/libc-2.12.so)
  19. ==3615== by 0x3FABC35D61: exit (in /lib64/libc-2.12.so)
  20. ==3615== by 0x40067A: main (unaddressbale_test.cc:8)
  21. ==3615== Uninitialised value was created by a heap allocation
  22. ==3615== at 0x4A068FE: malloc (vg_replace_malloc.c:270)
  23. ==3615== by 0x400653: main (unaddressbale_test.cc:6)
  24. ==3615==
  25. ==3615==
  26. ==3615== HEAP SUMMARY:
  27. ==3615== in use at exit: 14 bytes in 2 blocks
  28. ==3615== total heap usage: 2 allocs, 0 frees, 14 bytes allocated
  29. ==3615==
  30. ==3615== LEAK SUMMARY:
  31. ==3615== definitely lost: 0 bytes in 0 blocks
  32. ==3615== indirectly lost: 0 bytes in 0 blocks
  33. ==3615== possibly lost: 0 bytes in 0 blocks
  34. ==3615== still reachable: 14 bytes in 2 blocks
  35. ==3615== suppressed: 0 bytes in 0 blocks
  36. ==3615== Rerun with --leak-check=full to see details of leaked memory
anysis:
        7~15行表明系统调用write使用了未初始化道值,值是在堆上分配;
        17~23,同样exit传入未初始化的值,也是在堆上分配;


        (4)非法释放内存,分配,释放内存函数不匹配
code:

点击(此处)折叠或打开

  1. #include <stdlib.h>
  2. int main()
  3. {
  4.         int* __a = (int*)malloc(sizeof(int));
  5.         int* __b = new int;
  6.         int* __c = new int;
  7.         delete __a;
  8.         free(__b);
  9.         delete __c;
  10.         // delete again
  11.         delete __c;
  12.         return 0;
  13. }
usage:

点击(此处)折叠或打开

  1. valgrind --tool=memcheck --log-file=memcheck.log ./illegal_free_test
output:

点击(此处)折叠或打开

  1. ==8749== Memcheck, a memory error detector
  2. ==8749== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
  3. ==8749== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
  4. ==8749== Command: ./illegal_free_test
  5. ==8749== Parent PID: 30468
  6. ==8749==
  7. ==8749== Mismatched free() / delete / delete []
  8. ==8749== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
  9. ==8749== by 0x4006D1: main (illegall_free_test.cc:7)
  10. ==8749== Address 0x4c37040 is 0 bytes inside a block of size 4 alloc'd
  11. ==8749== at 0x4A068FE: malloc (vg_replace_malloc.c:270)
  12. ==8749== by 0x4006A5: main (illegall_free_test.cc:4)
  13. ==8749==
  14. ==8749== Mismatched free() / delete / delete []
  15. ==8749== at 0x4A06300: free (vg_replace_malloc.c:446)
  16. ==8749== by 0x4006DD: main (illegall_free_test.cc:8)
  17. ==8749== Address 0x4c37090 is 0 bytes inside a block of size 4 alloc'd
  18. ==8749== at 0x4A074CC: operator new(unsigned long) (vg_replace_malloc.c:298)
  19. ==8749== by 0x4006B3: main (illegall_free_test.cc:5)
  20. ==8749==
  21. ==8749== Invalid free() / delete / delete[] / realloc()
  22. ==8749== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
  23. ==8749== by 0x4006F5: main (illegall_free_test.cc:11)
  24. ==8749== Address 0x4c370e0 is 0 bytes inside a block of size 4 free'd
  25. ==8749== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
  26. ==8749== by 0x4006E9: main (illegall_free_test.cc:9)
  27. ==8749==
  28. ==8749==
  29. ==8749== HEAP SUMMARY:
  30. ==8749== in use at exit: 0 bytes in 0 blocks
  31. ==8749== total heap usage: 3 allocs, 4 frees, 12 bytes allocated
  32. ==8749==
  33. ==8749== All heap blocks were freed -- no leaks are possible
  34. ==8749==
  35. ==8749== For counts of detected and suppressed errors, rerun with: -v
  36. ==8749== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 4 from 4)
anysis:
        7,14行都检测到了内存分配,释放函数不匹配;
        21行 Invalid free,一块内存释放2次可以检测出来!


        (5)内存重叠
code:

点击(此处)折叠或打开

  1. #include <string.h>
  2. int main()
  3. {
  4.         char __context[] = "hello,valgrind";
  5.         strcpy(__context,__context + 5);
  6.         return 0;
  7. }
usage:

点击(此处)折叠或打开

  1. valgrind --tool=memcheck --log-file=memcheck.log ./memory_overlapped_test
output:

点击(此处)折叠或打开

  1. ==31370== Memcheck, a memory error detector
  2. ==31369== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
  3. ==31369== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
  4. ==31369== Command: ./memory_overlapped_test
  5. ==31369== Parent PID: 30468
  6. ==31369==
  7. ==31369== Source and destination overlap in strcpy(0x7fefffff0, 0x7fefffff5)
  8. ==31369== at 0x4A07F48: strcpy (mc_replace_strmem.c:438)
  9. ==31369== by 0x4005E1: main (memory_overlapped_test.cc:5)
  10. ==31369==
  11. ==31369==
  12. ==31369== HEAP SUMMARY:
  13. ==31369== in use at exit: 0 bytes in 0 blocks
  14. ==31369== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
  15. ==31369==
  16. ==31369== All heap blocks were freed -- no leaks are possible
  17. ==31369==
  18. ==31369== For counts of detected and suppressed errors, rerun with: -v
  19. ==31369== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
anysis:
        7~9行检测到内存重叠问题,使用strcpy函数时,0x7fefffff0, 0x7fefffff5这段地址产生重叠。

        (6)内存泄漏检测
        内存泄漏问题比较常见了,上述示例中就有涉及,其根本原因在于申请道内存未正常释放;memcheck检测的内存泄漏结果大致分为两种:确定的内存泄漏(Definitely lost),可能道内存泄漏Possibly lost);Possibly lost是指仍然存在某个指针能够访问某块内存,但是该指针指向的已经不是该内存首地址;Definitely lost是指已经不能够访问的这块内存;

参考:
     
     Valgrind官方网站:

    应用 Valgrind 发现 Linux 程序的内存问题: https://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/

 
 
 
         
阅读(1995) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~