Valgrind工具之内存检测

Valgrind安装方法:

按顺序执行以下命令:

1.  wget http://www.valgrind.org/downloads/valgrind-3.10.0.tar.bz2(从valgrind官网上下载压缩包)

2. tar xvf valgrind-3.13.0(解压压缩包)

3. cd valgrind-3.10.0

3. ./configure --prefix=/home/UserName/valgrind(配置安装路径,UserName替换为你自己的系统的用户名)

4. make(从makefile中读取指令,然后编译)

5. make install(从makefile中读取指令,安装到指定位置)

6. export PATH="$PATH:/home/UserName/valgrind/bin"(配置环境变量)

安装完成后,本篇将从五个方面描述valgrind对内存的检测:

1. 使用未初始化的内存

有如下程序1:

#include <iostream>
using namespace std;
int main()
{
	int a[5];
	int i,s=0;
	a[0]=a[1]=a[3]=a[4]=0;
	for(i=0;i<5;i++)
	  s=s+a[i];
	if(s==33)
	  cout<<"sum is 33"<<endl;
	else
	  cout<<"sum is not 33"<<endl;
	return 0;
}

        在程序1中,数组a中的第二个元素未进行初始化,但是在for循环中依然访问链数组a的第二个元素。这就是使用未初始化的元素问题。在使用g++编译器对该程序编译并运行,结果如下:

        可以从上图中发现,程序在编译和运行过程中并没有报出任何错误,异常和警告。但实际上,程序存在一个巨大的隐患,那就是对未初始化的内存进行访问。我们使用valgrind对该程序进行检测,结果如下所示:

      从上图结果中可以清晰的看到,提示出1个错误,提示信息为:“Conditional jump or move depends on uninitialised value(s)”,并且提示了错误位置在源文件test1.cpp中的第10行(此处要求我们在进行g++编译时添加-g参数,不然便给不出具体行数的提示)。

2. 内存读写越界

程序2如下所示:

#include <stdlib.h>
#include <iostream>
using namespace std;
int main()
{
	int len=4;
	int *pt=(int *)malloc(len*sizeof(int));
	int *p=pt;
	for(int i=0;i<len;i++)
	  p++;
	*p=5;
	cout<<"the value of p is"<<*p<<endl;
	return 0;
}

        在程序2中,p指针首先指向了malloc出的4个字节的地址。之后执行了四次自增运算。也就是p指针自增运算后与初始地址相比偏移了32个字节。偏移后的地址空间在程序中并没有申请。所以,p指针变成链野指针。程序中并且又对p的地址空间进行写操作。这就造成链内存读写越界的问题。在使用g++编译器对该程序编译并运行,结果如下:

        可以从上图中发现,程序在编译和运行过程中并没有报出任何错误,异常和警告。但实际上,程序越界读写,并且malloc出的地址空间没有释放,造成内存泄漏,是一个很大的隐患。我们使用valgrind对该程序进行检测,结果如下所示:

        从上图结果中可以清晰的看到,提示出2个错误,提示信息分别为:“Invalid write of size 4”和“Invalid read of size 4”,并且提示了错误位置在源文件test2.cpp中的第11行和第12行。并且检测提示了:“1 allocs, 0 frees, 16 bytes allocated”。有内存泄漏。

3. 内存覆盖

程序3如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	char x[50];
	int i;
	for(i=0;i<50;i++)
	  x[i]=i+1;
	strncpy(x+20,x,20);
	strncpy(x+20,x,21);
	strncpy(x,x+20,20);
	strncpy(x,x+20,21);
	x[39]='\0';
	strcpy(x,x+20);
	x[39]=39;
	x[40]='\0';
	strcpy(x,x+20);
	return 0;
}

        在程序3中,strncpy(x+20,x,21),strncpy(x,x+20,21),strcpy(x,x+20)这三条语句,在进行字符串复制过程中,复制与被复制的字符串空间存在交集。通过复制操作,会改变初始字符串空间中的值。这就是内存覆盖的问题。在使用g++编译器对该程序编译并运行,结果如下:

        可以从上图中发现,程序在编译和运行过程中并没有报出任何错误,异常和警告。但实际上存在内存覆盖的问题,当我们不注意,再去使用原始字符串时,已经不是原来那个字符串了。我们使用valgrind对该程序进行检测,结果如下所示:

         从上图结果中可以清晰的看到,提示出3个错误,提示信息分别为:“Source and destination overlap in strncpy(0xbe9cffd3, 0xbe9cffbf, 21)”,“Source and destination overlap in strncpy(0xbe9cffbf, 0xbe9cffd3, 21)”和“Source and destination overlap in strcpy(0xbe9cffaa, 0xbe9cffbe)”,并且提示了错误位置在源文件test3.cpp中的第11行,第13行和第18行。

4. 动态内存管理错误

程序4如下所示:

#include <iostream>
#include <stdlib.h>
int main()
{
	int i;
	char *p=(char *)malloc(10);
	char *pt=p;
	for(i=0;i<10;i++)
	{
		p[i]='z';
	}
	delete p;
	pt[1]='x';
	free(pt);
	return 0;
}

        在程序4中,使用malloc申请空间,使用delete释放空间,两者不匹配。使用malloc申请了10个字节的空间,只释放了一个字节空间。另外,对释放的空间仍然进行了读写操作。这些是典型的内存管理错误问题。在使用g++编译器对该程序编译并运行,结果如下:

        可以从上图中发现,程序在运行中报出内存错误,但没有给出具体信息。我们使用valgrind对该程序进行检测,结果如下所示:

从上图结果中可以清晰的看到,提示出的3个错误。使用malloc申请空间,使用delete释放空间,两者不匹配问题:“Mismatched free() / delete / delete []”;使用malloc申请链10个字节的空间,只释放链一个字节空间:“ Invalid free() / delete / delete[] / realloc()”;对释放空间仍然进行读写操作:“Invalid write of size 1”;

5. 内存泄漏

程序5如下所示:

#ifndef _TREE_
#define _TREE_
typedef struct _node{
	struct _node *l;
	struct _node *r;
	char v;
}node;
node *mk(node *l,node *r,char val);
void nodefr(node *n);
#endif
#include <stdlib.h>
#include "tree.h"
node *mk(node *l,node *r,char val)
{
	node *f=(node *)malloc(sizeof(*f));
	f->l=l;
	f->r=r;
	f->v=val;
	return f;
}
void nodefr(node *n)
{
	if(n){
		nodefr(n->l);
		nodefr(n->r);
		free(n);
	}
}
#include <iostream>
#include "tree.h"
int main()
{
	node *tree1,*tree2,*tree3;
	tree1=mk(mk(mk(0,0,'3'),0,'2'),0,'1');
	tree2=mk(0,mk(0,mk(0,0,'6'),'5'),'4');
	tree3=mk(mk(tree1,tree2,'8'),0,'7');
	return 0;
}

        在程序5中,使用malloc申请空间后,没有使用free函数释放申请的内存地址造成内存泄漏。在使用g++编译器对该程序编译并运行,结果如下:

        可以从上图中发现,程序在编译和运行过程中并没有报出任何错误,异常和警告。但实际上存在内存泄漏的问题。我们使用valgrind对该程序进行检测,结果如下所示:

        从上图结果中可以清晰的看到:“total heap usage: 8 allocs, 0 frees, 96 bytes allocated”。提示间接内存泄漏:“indirectly lost: 84 bytes in 7 blocks”;提示直接内存泄漏:“definitely lost: 12 bytes in 1 blocks”(间接内存泄漏指:指向该内存的指针都位于内存泄漏处;直接泄漏时指:没有任何指针指向该内存)。

本篇中的代码样例及相关内容都来自于学习徐晓鑫女士编著的《后台开发核心技术与应用实践》所得,特此声明。

程序相关源码下载地址:https://github.com/XiaoYaoNet/Valgrind_Memset

猜你喜欢

转载自blog.csdn.net/qq_38697681/article/details/80638510