Linux内存越界检测方法——valgrind
一.Valgrind
1.下载安装
下载地址:http://valgrind.org/downloads/current.html#current
#configure
#make
#make install
2.使用
2.1内在越界
写一段有内存访问越界的代码,如下:
#include
#include
#include
int main()
{
char *p = NULL;
char *temp = NULL;
p = (char*)malloc(sizeof(char));
if (NULL == p)
{
perror("Cannot allocate memory.");
return -1;
}
temp[0] = p[6];
free(p);
p = NULL;
return 0;
}
保存文件test.c
在上面的代码中,我们给p分配了一个字节的空间,后面却要访问p[6],看看会出现什么情况。
2.1.1带DEBUG编译
#gcc t-g test.c -o test
2.1.2运行分析
首先直接运行
#./test
段错误 (core dumped)
直接报错退出。
使用valgrind加载运行test
#valgrind --tool=memcheck --leak-check=full ./test
==17686== Memcheck, a memory error detector
==17686== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==17686== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==17686== Command: ./test
==17686==
==17686== Invalid read of size 1
==17686== at 0x40059A: main (test.c:19)
==17686== Address 0x4c22046 is 5 bytes after a block of size 1 alloc'd
==17686== at 0x4A0720A: malloc (vg_replace_malloc.c:296)
==17686== by 0x400575: main (test.c:10)
==17686==
==17686== Invalid write of size 1
==17686== at 0x4005A1: main (test.c:19)
==17686== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==17686==
==17686==
==17686== Process terminating with default action of signal 11 (SIGSEGV)
==17686== Access not within mapped region at address 0x0
==17686== at 0x4005A1: main (test.c:19)
==17686== If you believe this happened as a result of a stack
==17686== overflow in your program's main thread (unlikely but
==17686== possible), you can try to increase the size of the
==17686== main thread stack using the --main-stacksize= flag.
==17686== The main thread stack size used in this run was 10485760.
==17686==
==17686== HEAP SUMMARY:
==17686== in use at exit: 1 bytes in 1 blocks
==17686== total heap usage: 1 allocs, 0 frees, 1 bytes allocated
==17686==
==17686== LEAK SUMMARY:
==17686== definitely lost: 0 bytes in 0 blocks
==17686== indirectly lost: 0 bytes in 0 blocks
==17686== possibly lost: 0 bytes in 0 blocks
==17686== still reachable: 1 bytes in 1 blocks
==17686== suppressed: 0 bytes in 0 blocks
==17686== Reachable blocks (those to which a pointer was found) are not shown.
==17686== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==17686==
==17686== For counts of detected and suppressed errors, rerun with: -v
==17686== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 4 from 4)
段错误 (core dumped)
我们看到,valgrind共报了两个错误,见上面红色部分,我们分别分析一下:
==17686== Invalid read of size 1
==17686== at 0x40059A: main (test.c:19)
==17686== Address 0x4c22046 is 5 bytes after a block of size 1 alloc'd
==17686== at 0x4A0720A: malloc (vg_replace_malloc.c:296)
==17686== by 0x400575: main (test.c:10)
这个是读错误,指出在test.c的第19行,在第10行(p = (char*)malloc(sizeof(char));)正常分配给地址(0x4A0720A)1个字节,读的地址(0x4c22046)却是之后的5个字节处(我们访问的p[6])。
再分析第二个错误:
==17686== Invalid write of size 1
==17686== at 0x4005A1: main (test.c:19)
==17686== Address 0x0 is not stack'd, malloc'd or (recently) free'd
Valgrind报怨我们没有分配就开始使用,说的应该是temp了。
2.2内存泄露
2.2.1代码修改
对于内存泄露,valgrind也可以很好地检查出来,在上例中,做如下修改:
#include
#include
#include
int main()
{
char *p = NULL;
char *temp = NULL;
p = (char*)malloc(sizeof(char));
if (NULL == p)
{
perror("Cannot allocate memory.");
return -1;
}
//temp[0] = p[6];
//free(p);
p = NULL;
return 0;
}
注释内存访问越界和释放内存的代码。
2.2.2编译并运行
编译(见上)。
先直接运行:
#./test
没有任何提示。
再次使用Valgrind加载。
valgrind --tool=memcheck --leak-check=full ./test
==17793== Memcheck, a memory error detector
==17793== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==17793== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==17793== Command: ./test
==17793==
==17793==
==17793== HEAP SUMMARY:
==17793== in use at exit: 1 bytes in 1 blocks
==17793== total heap usage: 1 allocs, 0 frees, 1 bytes allocated
==17793==
==17793== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==17793== at 0x4A0720A: malloc (vg_replace_malloc.c:296)
==17793== by 0x400525: main (test.c:10)
==17793==
==17793== LEAK SUMMARY:
==17793== definitely lost: 1 bytes in 1 blocks
==17793== indirectly lost: 0 bytes in 0 blocks
==17793== possibly lost: 0 bytes in 0 blocks
==17793== still reachable: 0 bytes in 0 blocks
==17793== suppressed: 0 bytes in 0 blocks
==17793==
==17793== For counts of detected and suppressed errors, rerun with: -v
==17793== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
2.2.3分析
在上面标红的描述中,告诉我们1个字节初分配,但未释放,这1个字节是在test.c的第10行(p = (char*)malloc(sizeof(char));)分配的。
3.总结
由于HEAP SUMMARY是在程序正常退出时统计的内存泄露,所以如果程序异常退出,只能对已经运行的内存进行越界检查,无法进行内存泄露的统计。