代码检查工具文档

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

代码检查工具一.内存泄漏的发生方式1).常发性2).偶发性3).一次性4).隐式二.代码检查的方式代码检查的方式分为静态代码检查(Staticprogramanalysis)和动态代码检查(Dynamicprogramanalysis)。三.动态代码检查——Valgrind简单用法1).valgrind包含的工具①.memcheck最常用的工具,也是valgrind默认的工具。用来检测程序中出现的内存问题,所有对内存的读写都会被检测到。一切对malloc()/free()、new/delete的调用都会被捕获,所以它能检测以下问题:对未初始化内存的使用读/写释放后的内存块读/写超出malloc分配的内存块读/写不适当的栈中内存块内存泄漏,指向一块内存的指针永远丢失不正确的malloc/free或new/delete匹配Memcpy()相关函数中的dst和src指针重叠。②.callgrind,它不需要在编译源码时附加特殊选项,但推荐加上调试选项,callgrind搜集程序运行时的一些数据,建立函数调用关系图,还可以有选择的进行cache模拟,在运行结束时,它会把分析数据写入一个文件。简而言之,它主要用来检查程序中函数调用过程中出现的问题。③.cachegrind,它模拟CPU中的一级缓存和二级缓存,能够精确的指出程序中cache的丢失和命中。如果需要,它还能为我们提供cache丢失的次数,内存引用次数,以及每行代码、每个函数、每个模块、整个程序产生的指令数。对优化程序有很大帮助。④.helgrind,它主要用来检查多线程程序中出现的竞争问题。Helgrind寻找内存中被多个线程访问而又没有一贯加锁的区域,这些区域往往是线程之间失去同步的地方。而且会导致难以发掘的错误。⑤.massif,堆栈分析器,它能测量程序在堆栈中使用了多少内存,告诉我们堆块、堆管理块和栈的大小。它能帮助我们减少内存的使用,在带有虚拟内存的现代系统中,它还能加速我们的程序运行,减少程序停留在交换区中的几率。⑥.extension。可以利用core提供的功能,自己编写特定的内存调试工具。2).valgrind的使用Valgrind[valgrind-options]your-prog[your-prog-options]选项作用-h/--help显示帮助信息-version显示valgrind内核版本-q/--quiet安静的运行,只打印错误信息-v/--verbose打印更详细的信息--tool=[default:memcheck]运行valgrind中的工具,默认memcheck.--leak-check=no|summary|full要求对leak列出详细信息[default:summary]--log-file=filePath+日志信息文件3).使用示例①.未释放内存,数组越界.sample.c#includestdlib.hvoidfun(){int*p=(int*)malloc(10*sizeof(int));p[10]=0;}intmain(intargc,char*argv[]){fun();return0;}1.编译:gcc–gsample.c–osample2.使用valgrind:valgrind--leak-check=full./sample输出信心分析如下图所示:示例程序中有两个问题,一是fun()函数中动态申请的堆内存没有释放。二是对堆内存的访问越界。②.使用未初始化的内存。badloop.c#includestdio.hintmain(void){inta[5];inti,s;a[0]=a[1]=a[2]=a[3]=a[4]=0;for(i=0;i5;i++)s+=a[i];if(s==168)printf(sumis%d\n,s);return0;}1.编译:gcc–gbadloop.c–obadloop2.使用valgrind:valgrind--leak-check=full./badloop输出信心分析如下图所示:③.内存读写越界。badacc.c#includestdio.h#includestdlib.hintmain(void){intlen=4,i;int*pt=(int*)malloc(len*sizeof(int));int*p=pt;for(i=0;ilen;i++){p++;}*p=5;printf(thevalueofpequal:%d\n,*p);return0;}1.编译:gcc–gbadacc.c–obadacc2.使用valgrind:valgrind--leak-check=full./badacc输出信心分析如下图所示:④.内存覆盖。badlap.cpp#includestdio.h#includestdlib.h#includestring.hintmain(intargc,char*argv[]){charx[50];inti;for(i=0;i50;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);return0;}1.编译:g++–gbadlap.c–obadlap2.使用valgrind--leak-check=full./badlap输出信心分析如下图所示:代码画红线部分地址相差20,但是拷贝长度却是21,这样就会覆盖之前的值。Valgrind也很精确的检测出了这一点。⑤.动态内存管理错误。badmac.cpp常见的内存动态管理错误:申请和释放不一致(malloc/alloc/realloc申请用free。new用delete)申请和释放不匹配,申请了多少内存,在使用完成后就要释放多少。如果没有释放或者少释放了就是内存泄漏,多释放了也会产生问题。释放后仍然读写。#includestdlib.h#includestdio.hintmain(intargc,char*argv[]){inti;char*p=(char*)malloc(10);char*pt=p;for(i=0;i10;i++){p[i]=65+i;}deletep;pt[1]='x';free(pt);return0;}1.编译:g++–gbadmac.c–obadmac2.使用valgrind--leak-check=full./badmac输出信心分析如下图所示:由图可以看出,valgrind准确定位出这三个错误。⑥.内存泄漏内存泄漏(Memoryleak)指的是在程序中动态申请的内存,使用完成后即没有释放,又无法被程序的其它部分访问。Tree.h#ifndef__BADLEAK__#define__BADLEAK__typedefstruct__node{struct__node*l;struct__node*r;charv;}node;node*mk(node*l,node*r,charval);voidnodefr(node*n);#endifTree.cpp#includestdlib.h#includetree.hnode*mk(node*l,node*r,charval){node*f=(node*)malloc(sizeof(node));f-l=l;f-r=r;f-v=val;returnf;}voidnodefr(node*n){if(n){nodefr(n-l);nodefr(n-r);free(n);}}Badleak.cpp#includestdio.h#includetree.hintmain(intargc,char*argv[]){node*tree1,*tree2,*tree3;printf(test\n);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');return0;}Makefilebadleak:badleak.otree.og++-obadleakbadleak.otree.obadleak.o:badleak.cppg++-g-cbadleak.cpptree.o:tree.cppg++-g-ctree.cppclean:rm-rf*.orm-rfbadleak至此,valgrind常用的方法已总结完毕,置于valgrind的其它工具使用在此就不一一列举。四.静态代码检查Splint静态程序分析(staticprogramanalysis):静态程序分析是指使用自动化工具软件对程序源代码进行检查,以分析程序行为的技术,应用程序的正确性、安全缺陷检测、程序优化等。它的特点是不执行程序。1.Splint的检测范围:可能的空指针在释放内存之后使用了该指针赋值次序问题拼写错误被零除失败的case语句(遗漏了break语句)不可移植的代码宏定义参数没用圆括号符号的丢失异常的表达式变量没有初始化转换类型不一致可疑的判断语句(例如:if(x=0))Printf/scanf的格式检查2.Splint的使用在Linux命令行下,splint的使用很简单,检测文件*.c,用法如下:splint*.c检查控制splint提供了三种方式可进行检查的控制,分别是.splintrc配置文件、flags标志和格式化注释。flags:splint支持几百个标志用来控制检查和消息报告,使用时标志前加’+‘或’-’,'+'标志开启这个标志,'-'表示关闭此标志,下面例子展示了flags标志的用法:splint-showcola.c//在检测a.c时,告警消息中列数不被打印splint-varusea.c//在检测a.c时,告警消息中未使用变量告警不被打印.splintrc配置文件:在使用源码安装splint之后,.splintrc文件将被安装在主目录下,.splintrc文件中对一些标志作了默认的设定,命令行中指定的flags标志会覆盖.splintrc文件中的标志。格式化注释:格式化注释提供一个类型、变量或函数的格外的信息,可以控制标志设置,增加检查效果,所有格式化注释都以/*@开始,@*/结束,比如在函数参数前加/*@null@*/,表示该参数可能是NULL,做检测时,splint会加强对该参数的值的检测。3.使用示例①.认识splint输出的警告消息#includestdlib.hintfunc_splint_msg1(void){inta;return0;}intfunc_splint_msg2(void){int*a=(int*)malloc(sizeof(int));a=NULL;return0;}直接运行:splintsample.c②.使用空指针null_point.c#includestdio.hintfunc_null_point(void){int*a=NULL;return*a;}直接运行:splintnull_point.c②.转换类型不一致问题types.c#includestdio.hvoidsplint_types(void){shorta=0;longb=32768;a=b;return;}直接运行:splinttypes.c③.内存管理memory_managment.c#includestdio.h#includestdlib.h//当有其他指针引用当时候,释放一块空间voidmemory_management(void){int*a=(int*)malloc(sizeof(int));int*

1 / 16
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功