代码检查工具文档.docx

上传人:b****6 文档编号:5873349 上传时间:2023-01-01 格式:DOCX 页数:18 大小:882.72KB
下载 相关 举报
代码检查工具文档.docx_第1页
第1页 / 共18页
代码检查工具文档.docx_第2页
第2页 / 共18页
代码检查工具文档.docx_第3页
第3页 / 共18页
代码检查工具文档.docx_第4页
第4页 / 共18页
代码检查工具文档.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

代码检查工具文档.docx

《代码检查工具文档.docx》由会员分享,可在线阅读,更多相关《代码检查工具文档.docx(18页珍藏版)》请在冰豆网上搜索。

代码检查工具文档.docx

代码检查工具文档

代码检查工具

一.内存泄漏的发生方式

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=

Path+日志信息文件

3).使用示例

①.未释放内存,数组越界.sample.c

#include

voidfun()

{

int*p=(int*)malloc(10*sizeof(int));

p[10]=0;

}

intmain(intargc,char*argv[])

{

fun();

return0;

}

1.编译:

gcc–gsample.c–osample

2.使用valgrind:

valgrind--leak-check=full./sample

输出信心分析如下图所示:

示例程序中有两个问题,一是fun()函数中动态申请的堆内存没有释放。

二是对堆内存的访问越界。

②.使用未初始化的内存。

badloop.c

#include

intmain(void)

{

inta[5];

inti,s;

a[0]=a[1]=a[2]=a[3]=a[4]=0;

for(i=0;i<5;i++)

s+=a[i];

if(s==168)

printf("sumis%d\n",s);

return0;

}

1.编译:

gcc–gbadloop.c–obadloop

2.使用valgrind:

valgrind--leak-check=full./badloop

输出信心分析如下图所示:

③.内存读写越界。

badacc.c

#include

#include

intmain(void)

{

intlen=4,i;

int*pt=(int*)malloc(len*sizeof(int));

int*p=pt;

for(i=0;i

{

p++;

}

*p=5;

printf("thevalueofpequal:

%d\n",*p);

return0;

}

1.编译:

gcc–gbadacc.c–obadacc

2.使用valgrind:

valgrind--leak-check=full./badacc

输出信心分析如下图所示:

④.内存覆盖。

badlap.cpp

#include

#include

#include

intmain(intargc,char*argv[])

{

charx[50];

inti;

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);

return0;

}

1.编译:

g++–gbadlap.c–obadlap

2.使用valgrind--leak-check=full./badlap

输出信心分析如下图所示:

代码画红线部分地址相差20,但是拷贝长度却是21,这样就会覆盖之前的值。

Valgrind也很精确的检测出了这一点。

⑤.动态内存管理错误。

badmac.cpp

常见的内存动态管理错误:

●申请和释放不一致(malloc/alloc/realloc申请用free。

new用delete)

●申请和释放不匹配,申请了多少内存,在使用完成后就要释放多少。

如果没有释放或者少释放了就是内存泄漏,多释放了也会产生问题。

●释放后仍然读写。

#include

#include

intmain(intargc,char*argv[])

{

inti;

char*p=(char*)malloc(10);

char*pt=p;

for(i=0;i<10;i++)

{

p[i]=65+i;

}

deletep;

pt[1]='x';

free(pt);

return0;

}

1.编译:

g++–gbadmac.c–obadmac

2.使用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);

#endif

Tree.cpp

#include

#include"tree.h"

node*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

#include

#include"tree.h"

intmain(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;

}

Makefile

badleak:

badleak.otree.o

g++-obadleakbadleak.otree.o

badleak.o:

badleak.cpp

g++-g-cbadleak.cpp

tree.o:

tree.cpp

g++-g-ctree.cpp

clean:

rm-rf*.o

rm-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输出的警告消息

#include

intfunc_splint_msg1(void)

{

inta;

return0;

}

intfunc_splint_msg2(void)

{

int*a=(int*)malloc(sizeof(int));

a=NULL;

return0;

}

直接运行:

splintsample.c

②.使用空指针null_point.c

#include

intfunc_null_point(void)

{

int*a=NULL;

return*a;

}

直接运行:

splintnull_point.c

②.转换类型不一致问题types.c

#include

voidsplint_types(void)

{

shorta=0;

longb=32768;

a=b;

return;

}

直接运行:

splinttypes.c

③.内存管理memory_managment.c

#include

#include

//当有其他指针引用当时候,释放一块空间

voidmemory_management(void)

{

int*a=(int*)malloc(sizeof(int));

int*b=a;

free(a);

*b=0;

}

直接运行:

splintmemory_managment.c

#include

#include

voidmemory_management(void)

{

int*a=(int*)malloc(sizeof(int));

a=NULL;

}

直接运行:

splintmemory_managment.c

④.缓存边界buffersize.c

#include

#include

voidbounds1(void)

{

inta[10];

a[10]=0;

}

直接运行:

splint+boundsbuffersize.c

voidbounds2(char*str)

{

char*tmp=getenv("HOME");

if(tmp!

=NULL)

{

strcpy(str,tmp);

}

}

直接运行:

splint+boundsbuffersize.c

警告指出,在使用strcpy(str,tmp)时可能出现越界错误,因为str大小未知。

 

五.CppcheckC/C++静态代码分析工具

这个工具可以在windows下安装。

双击

即可安装。

安装后启动界面为:

Cppcheck检测的是整个目录。

单击

即可打开一个目录。

示例:

sample目录下有一个sample.c代码如下:

#include

voidfun()

{

int*p=(int*)malloc(10*sizeof(int));

p[10]=0;

}

intmain(intargc,char*argv[])

{

fun();

return0;

}

检测结果:

关于cppcheck用法这里不再一一赘述。

小结:

代码检查工具有很多,通过我多方搜索,就觉得这三款还不错。

有了这些工具的帮助虽然可以提高我们程序运行的质量。

但是代码的编写还要靠各位大神的细心和耐心。

写出优质的代码,让这些检查工具无可检查。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1