当前位置:   article > 正文

linux踩内存排查,linux下valgrind内存问题排查

valgring

c/c++的内存管理一直都是程序猿最头痛的事情,内存越界、数组越界、内存泄漏、内存溢出、野指针、空指针..., 随便一个问题都可能让程序崩溃。而且往往问题的源头都比较隐蔽,让人很难排查出问题的根源所在。

想要解决这个问题,还得从问题的根源入手。valgrind是一个强大的内存管理工具,常用来检测内存泄漏和内存的非法使用,用好了可以很好的从根源上解决c/c++内存管理的问题。

1.valgrind的主要功能

virgrind可以用来检测程序开发中的绝大多数内存,函数、缓存使用、多线程竞争访问内存、堆栈问题,是一个linux下功能非常强大内存检测工具。

1 valgrind工具

valgrind-tool= 最常用的选项。运行valgrind中名为toolname的工具。默认memcheck。

memcheck:这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误问题,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。下面将重点介绍此功能。

callgrind: 主要用来检查程序中函数调用过程中出现的问题。

cachegrind: 主要用来检查程序中缓存使用出现的问题。

helgrind: 主要用来检查多线程程序中出现的竞争问题。

massif: 主要用来检查程序中堆栈使用中出现的问题。

extension: 可以利用core提供的功能,自己编写特定的内存调试工具。

2 valgrind memcheck

2.1memcheck内存检测原理

valid-value表:

对于进程的整个地址空间中的每一个字节(byte),都有与之对应的8个bits,对于CPU的每个寄存器,也有一个与之对应的bit向量。这些bits负责记录该字节或者寄存器值是否具有有效的、已经初始化的值。

valid-Address表:

对于进程整个地址空间中的一个字节(byte),还有与之对应的1bit,负责记录该地址是否能够被读写。

内存检测原理:

当要读写内存中的某个字节时,首先检查这个字节对应的address bit。如果该address bit显示该位置是无效位置,memcheck则报告内存读写错误。valgrind内核相当于一个虚拟的CPU环境,当内存中的某个字节被加载到真实的CPU中时,该字节对应的value bit也被加载到虚拟的CPU环境中,一旦寄存器中的值,被用来产生内存地址,或者该值能够影响程序的输出,则mencheck会检查对应的value bits,如果该值尚未初始化,则会报告使用未初始化内存错误。

2.2 memcheck内存检测

2.2.1 准备源码

创建gdbmem.cpp源码文件,准备待检测的代码如下:

#include

#include

#include

#include

#include

#include

//memory access overflow

char* stringcopy(char* psrc)

{

int len = strlen(psrc) + 1;

char* pdst = (char*)malloc(len);//12

memset(pdst, 0, len * 2);//13

memcpy(pdst, psrc, len*2);//14

return pdst;

}

//array assess overflow

void printarray(int arry[], int arrysize)

{

int i = 0;

for(; i < arrysize; i++)

//for(i = arrysize-1; i >= 0; i--)

{

printf("arry[%d]:%d\n",i, arry[i]);

}

printf("arry[%d]:%d\n",i+1, arry[i+1]);//27

}

//main body

int main(int narg, const char** args)

{

char* pwildptr;

char* pstr = "this is a memory debug program!\n";

int array[10] = {1,2,3,4,5,6,7,8,9,10};

char* ptmp = stringcopy(pstr);//36

//memory leak

char* ptmp2 = (char*)malloc(100);//38

memset(ptmp2, 0, 100);

// memory write overflow

printf(ptmp);//41

// array tip assess overflow

printarray(array, 10);//43

free(ptmp);//44

printf("%p", pwildptr);//45

//wild ptr copy

memcpy(ptmp, ptmp2, 20);//47

printf(ptmp);//48

return 0;

}

2.2.2 编译源码:

$g++ -g -O0 -c gdbmem.cpp#-g:编译带调试信息的obj文件,-O0:不优化

$g++ -o gdbmem gdbmem.o

编译后将在当前目录下生成gdbmem可执行文件。

2.2.3 valgrind内存检测

valgring 对gdbmem进行内存检测

$ valgrind --tool=memcheck --leak-check=full --track-fds=yes ./gdbmem

==10668== Memcheck, a memory error detector

==10668== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.

==10668== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info

==10668== Command: ./gdbmem

==10668==

==10668== Invalid write of size 8

==10668== at 0x4C3453F: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==10668== by 0x40075D: stringcopy(char*) (gdbmem.cpp:13)

==10668== by 0x40087A: main (gdbmem.cpp:36)

==10668== Address 0x5204060 is 32 bytes inside a block of size 33 alloc'd

==10668== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==10668== by 0x400740: stringcopy(char*) (gdbmem.cpp:12)

==10668== by 0x40087A: main (gdbmem.cpp:36)

==10668==

==10668== Invalid write of size 1

==10668== at 0x4C34558: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==10668== by 0x40075D: stringcopy(char*) (gdbmem.cpp:13)

==10668== by 0x40087A: main (gdbmem.cpp:36)

==10668== Address 0x5204080 is 16 bytes after a block of size 48 in arena "client"

==10668==

==10668== Invalid write of size 8

==10668== at 0x4C326CB: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==10668== by 0x400778: stringcopy(char*) (gdb

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/152414
推荐阅读
相关标签
  

闽ICP备14008679号