Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6325207
  • 博文数量: 2759
  • 博客积分: 1021
  • 博客等级: 中士
  • 技术积分: 4091
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-11 14:14
文章分类

全部博文(2759)

文章存档

2019年(1)

2017年(84)

2016年(196)

2015年(204)

2014年(636)

2013年(1176)

2012年(463)

分类: LINUX

2013-08-20 11:06:11

原文地址:Valgrind之Memcheck 作者:scq2099yt

        Memcheck是Valgrind工具集中最常用的工具,用来检测程序中出现的内存问题,所有对内存的读写都会被检测到,一切对malloc、free、new、delete的调用都会被捕获。Memcheck之所以能够检测出这些内存问题,关键在于其建立了两个全局表:
        (1)Valid-Value表
        对于进程的整个地址空间中的每一个字节(byte)都有与之对应的8个bits,对于CPU的每个寄存器,也有一个与之对应的bit向量,这些bits负责记录该字节或者寄存器值是否具有有效的、已初始化的值。
        (2)Valid-Address表
        对于进程整个地址空间中的每一个字节(byte),还有与之对应的1个bit负责记录该地址是否可写。
        检测原理如下:
        (1)当要读写内存中某个字节时,首先检查这个字节对应的A bit,如果该A bit显示该位置是无效位置,Memcheck则报告读写错误。
        (2)内核(core)类似于一个虚拟的CPU环境,这样当内存中的某个字节被加载到真实的CPU中时,该字节对应的V bit也被加载到虚拟的CPU环境中。一旦寄存器中的值,被用来产生内存地址,或者该值能够影响程序输出,则Memcheck会检查对应的V bits,如果该值尚未被初始化,则会报告使用未初始化内存错误。

        需要注意的是,在编译程序的时候最好加入-g参数,便于Valgrind读入符号表之类的信息以提供更丰富的错误定位信息,不推荐加入-O等优化参数,因为优化后的代码易于让Valgrind解释错误。下面将针对Memcheck能够检测的七种问题进行详细介绍。
一、未初始化内存
         对于位于程序中不同段的变量,其初始值是不同的,全局变量和静态变量初始值为0,而局部变量和动态申请的变量,其初始值为随机值。如果程序使用了为随机值的变量,那么程序的行为就变得不可预期。下面程序将演示一种常见的使用了未初始化变量的场景,局部变量s初始化值为随机值,在条件语句中使用变量s来作if条件变量:
        
        编译程序,分析结果:
        
        输出结果显示,在该程序第6行中,if条件语句的跳转依赖于一个未初始化的变量s,准确地发现了该程序中存在的问题。

二、内存读写越界
         这种情况是指,访问了你不应该或者没有权限访问的内存地址空间,比如:访问数组越界、对动态内存访问时超出了申请的内存大小范围。下面程序将演示一种典型的数组越界问题,pt是一个局部数组变量,其大小为4,在用for循环初始化数组元素时,对数组进行了越界写操作,这将导致不可预期的后果:
        
        编译程序,分析结果:
        
        输出结果显示,在该程序的第8行,进行非法的写操作,在该程序的第9行,进行了非法读操作,准确地发现了内存读写越界问题。
    
三、内存覆盖        
        C标准库中提供了大量直接操作内存的函数,比如:memcpy、strcpy、strncpy、strcat等,这些函数有一个共同特点就是需要设置源地址src和目标地址dst,src和dst指向的地址不能发生重叠,否则结果将不可预期。下面程序将演示一种典型的内存重叠或覆盖的问题,src和dst所指向的地址相差20,但指定的拷贝长度却是21,这样就会把之前拷贝的值覆盖:
        
        编译程序,分析结果:
        
        
输出结果显示,在该程序的第12行,源地址和目标地址数据拷贝出现重叠,准确地发现了内存覆盖问题。

四、申请和释放方式不匹配
        为了兼容C,在C++中有两套动态内存管理机制,分别是C方式的malloc/alloc/realloc/free,C++方式的new/delete,这两种方式不能混用,否则会有潜在问题存在。下面程序将演示一种典型的申请和释放不匹配的问题,用malloc申请的内存由delete释放,用new申请的内存由free释放:
        
        编译程序,分析结果:
        
        
输出结果显示,在该程序的第6行由malloc分配内存,在第7行由delete释放,第8行由new分配内存,在第9行由free释放,准确发现了内存申请和释放不匹配的问题。

、释放后仍然读写
         系统在堆上维护一个动态内存链表,如果动态申请的内存被释放,就意味着这块内存可以继续被分配给其它部分,如果内存被释放后再访问,就可能覆盖其它部分信息,这是一种严重的错误。下面程序将演示一种典型的释放后仍然使用的问题,用new申请的内存由delete释放后仍然修改其值:
        
        编译程序,分析结果:
        

        输出结果显示,在该程序的第7行delete了第6行由new分配的内存后第8行仍然写这块内存,准确发现了内存释放后仍然读写该块内存的问题

六、内存泄露
        内存泄露,狭义上来说是指向一块内存的指针永远丢失,但是在此引申一下。申请了多少内存,在使用完成后就要释放多少,如果没有释放或者释放少了都属于内存泄露。当然多释放了也会产生问题。下面程序将演示这几种情况:
        
        编译程序,分析结果:
        

        输出结果显示,在该程序的第7行new出了10个元素的数组,第8行delete时需要用delete [],第9行new出的内存,第10行和第11行分别delete,这样就多少释放了一次,第6行new出的内存没有释放.
        在LEAK SUMMARY中:
        (1)definitely lost:没有任何指针指向该区域,已经造成了内存泄露。
        (2)indirectly lost:指向该内存的指针也位于内存泄露处。
        (3)possibly lost:仍然存在某个指针能够访问某块内存,但该指针指向的已经不是该内存首地址。
        (4)still reachable:仍有指针引用该内存块,只是没有释放而已,可以通过设置--show-reachable=yes来报错。

        



阅读(794) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~