一,memcheck 功能概述
valgrind包含很多工具,其中memcheck是一个内存错误检测工具。它能检测出C/C++中的常见内存问题:
(1)内存访问错误,如内存溢出,访问已释放的内存;
(2)使用未初始化的值;
(3)不正确的释放内存,如两次释放内存块,或者不匹配的使用malloc/new/new[] , 对应于 free/delete/delete[];
(4) 使用memcoy相关函数导致的内存重叠 ;
(5)内存泄漏;
二,使用示例
(1)非法读/写错误
code:
-
int main()
-
{
-
int* __array = new int[10];
-
// use __array and delete it
-
if(__array)
-
{
-
// ...
-
// use delete but not delete []
-
delete __array;
-
}
-
// use __array again
-
int __val = __array[0];
-
__array[0] = 0;
-
return 0;
-
}
usage:
-
valgrind --tool=memcheck --read-var-info=yes --log-file=memcheck.log ./illegal_r_w_test
output:
-
==24579== Memcheck, a memory error detector
-
==24579== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
-
==24579== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
-
==24579== Command: ./illegal_r_w_test
-
==24579== Parent PID: 19990
-
==24579==
-
==24579== Mismatched free() / delete / delete []
-
==24579== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
-
==24579== by 0x40062C: main (illegal_r_w_test.cc:9)
-
==24579== Address 0x4c37040 is 0 bytes inside a block of size 40 alloc'd
-
==24579== at 0x4A07062: operator new[](unsigned long) (vg_replace_malloc.c:363)
-
==24579== by 0x400615: main (illegal_r_w_test.cc:3)
-
==24579==
-
==24579== Invalid read of size 4
-
==24579== at 0x400631: main (illegal_r_w_test.cc:12)
-
==24579== Address 0x4c37040 is 0 bytes inside a block of size 40 free'd
-
==24579== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
-
==24579== by 0x40062C: main (illegal_r_w_test.cc:9)
-
==24579==
-
==24579== Invalid write of size 4
-
==24579== at 0x40063A: main (illegal_r_w_test.cc:13)
-
==24579== Address 0x4c37040 is 0 bytes inside a block of size 40 free'd
-
==24579== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
-
==24579== by 0x40062C: main (illegal_r_w_test.cc:9)
-
==24579==
-
==24579==
-
==24579== HEAP SUMMARY:
-
==24579== in use at exit: 0 bytes in 0 blocks
-
==24579== total heap usage: 1 allocs, 1 frees, 40 bytes allocated
-
==24579==
-
==24579== All heap blocks were freed -- no leaks are possible
-
==24579==
-
==24579== For counts of detected and suppressed errors, rerun with: -v
-
==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:
-
#include<stdio.h>
-
int main()
-
{
-
bool __init = false;
-
int __a;
-
int __b;
-
int* __c = new int;
-
if(__init)
-
{
-
__a = 0;
-
}
-
printf("value __a = %d\n",__a);
-
printf("value __b = %d\n",__b);
-
printf("value __c = %d\n",*__c);
-
return 0;
-
}
usage:
-
valgrind --tool=memcheck --track-origins=yes --log-file=memcheck.log ./uninitialised_val_test
output:
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:
-
#include<unistd.h>
-
#include<stdlib.h>
-
int main()
-
{
-
char* __arr1 = (char*)malloc(10);
-
int* __arr2 = (int*)malloc(sizeof(int));
-
write(1,__arr1,10);
-
exit(__arr2[0]);
-
}
usage:
-
valgrind --tool=memcheck --track-origins=yes --log-file=memcheck.log ./unaddressbale_test
output:
-
==3615== Memcheck, a memory error detector
-
==3615== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
-
==3615== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
-
==3615== Command: ./unaddressbale_test
-
==3615== Parent PID: 30468
-
==3615==
-
==3615== Syscall param write(buf) points to uninitialised byte(s)
-
==3615== at 0x3FABCDA3C0: __write_nocancel (in /lib64/libc-2.12.so)
-
==3615== by 0x40066D: main (unaddressbale_test.cc:7)
-
==3615== Address 0x4c37040 is 0 bytes inside a block of size 10 alloc'd
-
==3615== at 0x4A068FE: malloc (vg_replace_malloc.c:270)
-
==3615== by 0x400645: main (unaddressbale_test.cc:5)
-
==3615== Uninitialised value was created by a heap allocation
-
==3615== at 0x4A068FE: malloc (vg_replace_malloc.c:270)
-
==3615== by 0x400645: main (unaddressbale_test.cc:5)
-
==3615==
-
==3615== Syscall param exit_group(status) contains uninitialised byte(s)
-
==3615== at 0x3FABCABC68: _Exit (in /lib64/libc-2.12.so)
-
==3615== by 0x3FABC35D61: exit (in /lib64/libc-2.12.so)
-
==3615== by 0x40067A: main (unaddressbale_test.cc:8)
-
==3615== Uninitialised value was created by a heap allocation
-
==3615== at 0x4A068FE: malloc (vg_replace_malloc.c:270)
-
==3615== by 0x400653: main (unaddressbale_test.cc:6)
-
==3615==
-
==3615==
-
==3615== HEAP SUMMARY:
-
==3615== in use at exit: 14 bytes in 2 blocks
-
==3615== total heap usage: 2 allocs, 0 frees, 14 bytes allocated
-
==3615==
-
==3615== LEAK SUMMARY:
-
==3615== definitely lost: 0 bytes in 0 blocks
-
==3615== indirectly lost: 0 bytes in 0 blocks
-
==3615== possibly lost: 0 bytes in 0 blocks
-
==3615== still reachable: 14 bytes in 2 blocks
-
==3615== suppressed: 0 bytes in 0 blocks
-
==3615== Rerun with --leak-check=full to see details of leaked memory
anysis:
7~15行表明系统调用write使用了未初始化道值,值是在堆上分配;
17~23,同样exit传入未初始化的值,也是在堆上分配;
(4)非法释放内存,分配,释放内存函数不匹配
code:
-
#include <stdlib.h>
-
int main()
-
{
-
int* __a = (int*)malloc(sizeof(int));
-
int* __b = new int;
-
int* __c = new int;
-
delete __a;
-
free(__b);
-
delete __c;
-
// delete again
-
delete __c;
-
return 0;
-
}
usage:
-
valgrind --tool=memcheck --log-file=memcheck.log ./illegal_free_test
output:
-
==8749== Memcheck, a memory error detector
-
==8749== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
-
==8749== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
-
==8749== Command: ./illegal_free_test
-
==8749== Parent PID: 30468
-
==8749==
-
==8749== Mismatched free() / delete / delete []
-
==8749== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
-
==8749== by 0x4006D1: main (illegall_free_test.cc:7)
-
==8749== Address 0x4c37040 is 0 bytes inside a block of size 4 alloc'd
-
==8749== at 0x4A068FE: malloc (vg_replace_malloc.c:270)
-
==8749== by 0x4006A5: main (illegall_free_test.cc:4)
-
==8749==
-
==8749== Mismatched free() / delete / delete []
-
==8749== at 0x4A06300: free (vg_replace_malloc.c:446)
-
==8749== by 0x4006DD: main (illegall_free_test.cc:8)
-
==8749== Address 0x4c37090 is 0 bytes inside a block of size 4 alloc'd
-
==8749== at 0x4A074CC: operator new(unsigned long) (vg_replace_malloc.c:298)
-
==8749== by 0x4006B3: main (illegall_free_test.cc:5)
-
==8749==
-
==8749== Invalid free() / delete / delete[] / realloc()
-
==8749== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
-
==8749== by 0x4006F5: main (illegall_free_test.cc:11)
-
==8749== Address 0x4c370e0 is 0 bytes inside a block of size 4 free'd
-
==8749== at 0x4A05EE6: operator delete(void*) (vg_replace_malloc.c:480)
-
==8749== by 0x4006E9: main (illegall_free_test.cc:9)
-
==8749==
-
==8749==
-
==8749== HEAP SUMMARY:
-
==8749== in use at exit: 0 bytes in 0 blocks
-
==8749== total heap usage: 3 allocs, 4 frees, 12 bytes allocated
-
==8749==
-
==8749== All heap blocks were freed -- no leaks are possible
-
==8749==
-
==8749== For counts of detected and suppressed errors, rerun with: -v
-
==8749== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 4 from 4)
anysis:
7,14行都检测到了内存分配,释放函数不匹配;
21行 Invalid free
,一块内存释放2次可以检测出来!
(5)内存重叠
code:
-
#include <string.h>
-
int main()
-
{
-
char __context[] = "hello,valgrind";
-
strcpy(__context,__context + 5);
-
return 0;
-
}
usage:
-
valgrind --tool=memcheck --log-file=memcheck.log ./memory_overlapped_test
output:
-
==31370== Memcheck, a memory error detector
-
==31369== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
-
==31369== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
-
==31369== Command: ./memory_overlapped_test
-
==31369== Parent PID: 30468
-
==31369==
-
==31369== Source and destination overlap in strcpy(0x7fefffff0, 0x7fefffff5)
-
==31369== at 0x4A07F48: strcpy (mc_replace_strmem.c:438)
-
==31369== by 0x4005E1: main (memory_overlapped_test.cc:5)
-
==31369==
-
==31369==
-
==31369== HEAP SUMMARY:
-
==31369== in use at exit: 0 bytes in 0 blocks
-
==31369== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
-
==31369==
-
==31369== All heap blocks were freed -- no leaks are possible
-
==31369==
-
==31369== For counts of detected and suppressed errors, rerun with: -v
-
==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/
阅读(2060) | 评论(0) | 转发(0) |