首页 > 代码库 > Linux内存越界检测方法——valgrind

Linux内存越界检测方法——valgrind



Linux内存越界检测方法——valgrind


一.Valgrind

1.下载安装

下载地址:http://valgrind.org/downloads/current.html#current

#configure

#make

#make install

2.使用

2.1内在越界

写一段有内存访问越界的代码,如下:

#include <stdio.h>

#include <stdlib.h> 

#include <errno.h>

 

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.1DEBUG编译

#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));)正常分配给地址(0x4A0720A1个字节,读的地址(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 <stdio.h>

#include <stdlib.h> 

#include <errno.h>

 

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是在程序正常退出时统计的内存泄露,所以如果程序异常退出,只能对已经运行的内存进行越界检查,无法进行内存泄露的统计。

 

Linux内存越界检测方法——valgrind