1. 目前代码的安全形势2 `4 S# {, ~% U4 a 1.1 缓冲区溢出问题( t) b6 W7 V) n: S- C “缓冲区溢出”是越过了数组边界进行读写的一类内存访问错误。大家知道,在标准C 语言库中提供了许多关于字符串的操作的函数,如:gets() 、strcpy () 、strcat ( ) 、strcmp ( ) 、sprintf ( ) 等。它们在本质上是不安全的,存在安全隐患,例如gets (str) 指令,在编译这条指令时,str 以字符数组的身份分配内存空间,并且str是所分配内存的一个连续存储区的首地址。gets 读取标准输入的文本,把第一个字符存入str 首地址内存单元中,后续字符依次存储,直到标准输入遇到结束符“ / 0”并存放到最后一个字节的存储单元中。在执行这条指令时,由于程序员不能预先确定缓冲区的大小,若读入的文本长度超出编译给定的存储区长度,则读入的字符会覆盖str 所代表的存储区的后续空间,因此,出现了所谓的缓冲区溢出。下面是一段存在缓冲区溢出问题的代码:4 i. u# m: O* y #include using namespace std; " J; G4 X* N4 T/ W( U- m int main() { 5 C M' p0 q s0 b, /- s5 } char pwd[10]; 6 V' _0 ?7 _7 f: Z# Y0 i' r, j cout<<"Please input your inite password(limited 10 chars):"; cin>>pwd; 8 H' I2 s" w( ?* S$ X5 f char userpwd[10]; cout<<"Please input your password:"; 6 q; [! S/ A1 t. c# {; g _$ n+ ? cin>>userpwd; $ Q/ Y /0 I) U- O cout<<"pwd :"< 9 h! v8 E' W) q* o5 w. ] cout<<"userpwd:"< return 0; , S$ t# R& J6 ? } ! m/ ?2 v# {* z- x6 c& q: D
实验表明,缓冲区溢出会出现两种风险: ①相邻该缓冲区的内存空间容易被覆盖,如果被覆盖的内容很关键,就可能造成非常严重的安全隐患。②通过覆盖运行栈中函数的返回地* r+ s. k- j+ T/ d, r 址来诱导程序执行其它任意代码,出现“栈溢出”覆盖错误。而上面的这段代码所带来的问题就是第一种,假设程序的密码为“1111111111”(10个‘1’),如果用户输入密码“2222222222222222222222”(22个‘2’),那么,程序原先的密码就会被恶意篡改为“2222222222”(10个‘2’),从而通过验证。 1.2 访问内存错误; z6 @3 X1 ]7 n% E1 I 访问内存错误是引发C 程序安全隐患的又一重要因素,它可能由数组、指针或内存管理造成,而缺乏边界检查是C 程序中使用指针和数组导致访问内存出错的根源。9 q4 G, g8 I. ?& Y 根据内存的分配、使用和释放过程,访问内存可能出现以下错误: ①使用了分配未成功的内存; ②引用了分配成功但未初始化的内存; ③内存分配成功又进行了初始化,但对它的操作越过了边界,出现“空间访问”故障; ④未释放内存直至内存耗尽,出现“内存泄露”错误; ⑤访问被释放的却具有不确定值的内存,出现“时间访问”故障。 1.3 指针的引用错误 指针是C 程序的重要的数据类型之一。在C 程序中,对指针的使用最灵活、最核心、最重要,称之为C 程序中最精华的部分,有“掌握C 指针就掌握C 语言”之说。但C中指针的使用又最复杂,最易出错。因此引用指针时须特别注意两个最基本要点: ①定义指针本身; ②必须使已定义的指针指向其应该指向的合法的存储空间。 q+ C0 C8 ^9 w" f 1.4 随机数的使用和异常的控制 系统随机数的产生函数rand() 提供的是伪随机数,其内部实现可以生成重复的输出值。 C 语言程序设计没有提供异常处理机制,异常检测和处理全部由程序员预设完成,一旦异常发生而又无预防处理就会出现不可预测的错误和安全问题 2. 源代码的静态检测工具PC_Lint 的使用7 O6 d) v. }0 N1 `/ x+ Y 2.1 PC_Lint能做什么. / P& K! S( X3 [) R8 C) R8 V
INTRODUCTION PClint/FlexeLint finds quirks, idiosyncrasies, glitches and bugs in C and C++ programs. The purpose ofsuch analysis is to determine potential problems in such programs before integration or porting, or toreveal unusual constructs that may be a source of subtle and, yet, undetected errors. Because it looksacross several modules rather than just one, it can determine things that a compiler cannot. It is normallymuch fussier about many details than a compiler wants to be. |
上面的这段介绍是从 PC_Lint 的自述文档中摘拷贝出来的,它的优点我用亮色突出显示了。PC-lint软件性价比高,易于学习,容易推广和固化到软件开发测试流程中去,所以在全世界得到了广泛的应用。PC-lint使用方法很简单,可以用命令行方式进行,例如lint-nt –u std.lnt test1.c test2.c test3.c 也可以使用MAKEFILE的方式。此外,它还可以集成到很多开发环境或常用的代码编辑软件中,比如集成到Source Insight/SLICKEDIT/MS VC6.0/KEIL C..等。PC-Lint还支持Scott Meyes的名著(Effective C++/More Effective C++)中说描述的各种提高效率和防止错误的方法。; U4 @+ k L6 U, B& I2 G% K 2.2 安装和配置PC_Lint5 r4 d3 Q: K8 ]4 f- l- A$ B' U' u 对于初学者来说,PC_Lint的安装和配置并不简单,特别是要弄懂在配置过程中生成的那些文件的意思和设置环境变量等问题更成问题。; L- D$ u; z6 e a+ D 在点击可执行安装文件在安装过程中的最后一步会弹出一个对话框询问是否现在要配置PC_Lint,如果点击是的话,紧接着的操作就是根据你的电脑环境和你的需要来配置你的PC_Lint,并由此来生成配置文件 ** . lnt,一般来说初学者都可以通过这个配置向导来配置一个适合你计算机环境的PC_Lint ,而对于PC_Lint的使用老手,可以直接编( a* }3 D( g. b J. B& X 配置文件 ** . lnt.下面是配置向导的配置过程。 首先,第一步是欢迎界面:7 J4 P8 R, q4 I 第二步是PC_Lint的一些自述性内容,说明PC_Lint的一种用法和这个配置向导的作用等等。 第三步是问你生成一个新的配置文件还是使用一个以前已有的配置文件来产生新的配置文件。在此之前,你必须先选择一个工作目录,一般情况下选择你的安装目录这样方便后面配置工作目录。 第四步,选择你的编译器环境。PC_Lint支持的编译器环境很多。根据你计算机环境选择合适你的计算机选项。3 L8 ^, n% I9 f' b! W 第五步,选择你计算机的硬件平台(默认情况下是32位的内存模型)。 第六步,选择你所用的库文件,STL、MFC、ATL是比较常用的几个库,这也是建议选择的几个库。 第七步,让你选择是否使用曾经为C/C++编程提出过重要建议的人所编写的配置文件。如果选择这些作者的建议,那么他提出的编程建议方面的选项将被打开,作者建议的配置文件名为AU-xxx.LNT将被从一个lnr的目录拷贝到你的安装目录,建议全部选择。3 f2 }" ~: X- X/ }- |: V! {0 U 第八步,接下来是选择用何种方式设置包含文件目录,如果选择使用 –i方式协助设置包含文件选项,下一步就会要求输入一个或多个包含路径。也可以跳过这一步,以后手工修改配置文件,-i选项体现在STD.LNT文件或新创建的STD_x.LNT文件中,每个目录前以-i引导,目录间以空格分隔,如果目录名中有长文件名或包含空格,使用时要加上双引号,如 -i“E:/Program Files/Microsoft Visual C++/VC98/include”。; l8 N( {* O) K/ f" I 接下来就是在下面的文本框里可手工输入文件包含路径,用分号“;”或用ctrl+Enter换行来分割多个包含路径,或者在目录树中直接选择。填完后点击“下一步”按钮: 第九步,因为第三步选择了“Create a new STD.LNT”选项,所以出现以下对话框,表示std_x.lnt在配置路径下已被创建,这里的std_*.lnt实际上包含了 std.lnt的信息,除此之外还有我们选择的包含路径和使用的库等配置信息。! F( r$ x- e# @ h' v4 o( Q 第十步,对话框询问是否使用现在生成的std_x.lnt文件取代std.lnt文件。+ U1 o% Z" l4 [# i% L# a5 ?6 X9 Y 第十一步,接下来将会准备产生一个控制全局编译信息显示情况的选项文:OPTIONS.LNT,该文件的产生方式有两种,一种是安装程序对几个核心选项逐一解释并提问你是否取消该选项,如果你选择取消,则会体现在OPTIONS.LNT文件中,具体体现方式是在该类信息编码前加-e,后面有一系列逐一选择核心选项的过程。如果选择第二种选择方式,安装文件会先生成一个空的OPTIONS.LNT文件,等你以后在实际应用时加入必要的选项。: m2 j9 [& v5 q: u$ P# O- C 第十二步,选择所支持的集成开发环境选项,可选多个或一个也不选,PC-Lint提供了集成在多种开发环境中工作的功能(最近发布的VisualLintAddinSetup v1.5.7.74.exe可提供更好的集成使用效果),例如可集成在VC、BC、Source Insight中。这里我们选择Microsift Visual C++ 6.0,这样env-v6.lnt就会被拷贝到配置路径中。 第十三步,安装程序会生成一个LIN.BAT文件,该文件是运行PC-Lint的批处理文件,为了使该文件能在任何路径下运行,安装程序提供了两种方法供你选择。第一种方法是让你选择把LIN.BAT拷贝到任何一个PATH目录下。第二种方法是生成一个LSET.BAT文件,在每次使用PC-LINT前先运行它来设置路径,或者把LSET.BAT文件的内容拷贝到OEXEC.BAT文件中。建议选择第一种方法,指定的目录为当前PC-Lint的安装目录。我们选择第一种方式:“copy LIN.BAT to one of my PATH directory”,然后单击“下一步”输入PATH目录。(至于怎么使用它们来检测我们的代码,将在2.3节中对三种方法进行详细介绍。) 最后一步,确认完成配置 就这样我们安装并配置好了PC_Lint,下面我们来看看这配置过程中所生的文件的含义:co-xxx.lnt(co--compiler描述有关编译器环境)、lib-xxx.lnt(lib--library库)、env- xxx.lnt(env--environment开发环境),在这个目录下还有其它PCLint所支持的编译器、库及集成开发环境的lnt配置文件,所有的lnt文件均为文本文件。2.3 在命令行方式下使用PC_Lint 在工作目录下使用PC_Lint,工作目录也就是你存放源代码的目录,你必须将在配置过程中生成的 lin.bat 拷贝到这个目录下,然后使用形如下面的命令方式检测你的代码: * v1 D7 J0 j/ ]8 /5 L
Lin options filename1.h filename2.cpp …… |
; n0 ?6 O% w R: X( P 在PC_Lint的安装目录下使用PC_Lint,在使用之前必须将你的存放源代码的目录添加到文件lset.bat中,并运行这个批处理文件。然后就可以使用下面的命令方式检测你的代码了。 ' x# m/ w( c2 r6 D
Lint-nt options filename1.h filename.cpp …… |
' M' _/ W4 W! d Z* O5 w 我们也可以通过设置环境变量来达到在任何目录下来检测我们的代码的目的。在你的工作目录下直接敲入如下命令: 2 i! u' |' t7 d; u" f* |. c
Set path = Installdir (同样你也可以通过其他方式来设置你的环境变量) |
; p3 X* E ]; D 然后你就可以在你的任何工作目录下使用 lint-nt 命令而不必在此之前来将文件lin.bat 拷贝到你的工作目录下或将你的源代码拷贝到PC_Lint的安装目录下了,这种方式适合于工作目录多且不确定的情况下使用。 2.4 将PC_Lint 加载到Visual Studio(6.0 and .net)中# ~- h& K& b0 X( C' j7 w8 p 因为PC_Lint可以支持单文件检测,工程检测,模块检测,所以我们下面在Visual Studio中分别添加三种外部工具的方式来介绍怎样将PC_Lint加载到Visual Studio中。 第一种,添加检测单文件的外部工具(PC_Lint(Simple Check))。 在Visual Studio 8.0 依次打开 Tools—>Exteral Tools, 弹出如下所示的对话框,然后添加一个新的外部工具。并按如下方式填入命令行、参数和初始目录:
Command: C:/Lint/Lint-nt.exe 7 {* @. ^' P5 e7 F' C4 ^. /% P Argument: -i“C:/Lint” –u std.lnt env-vc6.lnt $(ItemFileName)$(ItemExt) Init Directory: $(FileDir) X_Use Output Window __Prompt for arguments __Close on exit |
k q4 g6 k7 ?. L5 I9 B& `0 B 第二种,添加工程检测的外部工具。因为一个工程中可能包含多个文件,所以在进行检测之前必须先收集工程的信息。而工程的信息如所包含的文件的文件名、选项信息等都包含在工程目录下的一个后缀名为 .vcproj的文件中,PC_Lint可以读取这个文件中的信息,并声称一个projectname.lnt 的文件,然后,再根据这个文件来对这个工程进行检测。所以必须配置如下的两个工具PC-lint (Project Creation) 、 PC-lint (Project Check)。 在进行检测时,先用工具PC-lint (Project Creation)生成一个projectname.lnt,再用工具PC-lint(Project Check)来检测。
PC-lint (Project Creation) : & N. w, L/ q$ d/ x# O) w8 k Command: C:/Lint/Lint-nt.exe : o4 Q: {; w5 z; ~& M3 e; E Argument: - -v -os($(TargetName).lnt) "$(TargetName).vcproj"t Init Directory: $(FileDir) ) p6 f$ m- M5 j2 { PC-lint (Project Check): Command: C:/Lint/Lint-nt.exe Argument: -i"c:/lint" std.lnt env-vc7.lnt "$(TargetName).lnt" 3 p0 ^! u* W! Y, f% r1 E3 S Init Directory: $(FileDir) |
9 o9 [/ t% H0 ?7 m$ ~* J# q 第三种,添加模块检测外部工具。配置的输入选项如下:
Title: PC-lint (Unit Check) ) ^ h2 S) N& C- b' D Command: c:/lint/lint-nt.exe + f: P+ k8 ^. o5 } Arguments: -i"c:/lint" std.lnt env-vc7.lnt --u "$(TargetName).lnt" "$(ItemPath)" Init. Dir.: $(ProjectDir) X_Use Output Window __Prompt for arguments __Close on exit |
" x1 z( /( C" H/ R- l7 z6 k 将PC_Lint加载到Visual Studio 6.0 中的操作步骤和上面大概差不多,毕竟只是版本不同而已。但在配置时的输入有所不同,如下:) o p1 B; n: A8 D
6.0 8.0 Arguments "$(FileName)$(FileExt)" $(ItemFileName)$(ItemExt) Initial directory $(FileName) $(ItemDir) |
|
2.5 将PC_Lint 加载到 Editplus 中
4 C% o! /# e& I7 o/ l0 s
Editplus和Source Insightde 的检查环境类似,所以借用env-si中的环境配置,配置的参数如下图示:
0 H4 ]9 d$ f1 n* [* x' q/ |- Z: u
菜单文本:PC_Lint(Simple Check)
+ Z1 [4 g# B6 O1 t& B2 x
0 k( V, y3 D5 [" C- M v
命令: C:/Lint/lint-nt.exe
5 Q. m. W- o, H9 f
/ d, ?* N) y( e0 W4 s; |& O7 B: ~
参数: -i"c:/lint" std.lnt env-si.lnt $(FileName)
2 u' |; N: s! S, E+ q4 V: W
起始目录:$(FileDir)2.6 PC_Lint常用选项(opitions)的解释
2 D; T+ T( Z2 j1 L5 n
常用参数的设置
4 L5 h3 N# |- E- J- /9 i" e3 |
/ ?1 X/ l2 G) Y
Message的分类:
: h9 h# d4 d) B5 ~1 w, S9 I0 C( V
( E* ~7 V% _; k7 B0 |# T! x$ T
C C++ Warning Level
/ }9 T+ r+ V% R% M8 ]
Syntax Errors 1 – 199 1001 – 1199 1
Internal Errors 200 - 299 0
" Z0 [1 B5 P% V+ t+ h/ v) G
Fatal Errors 300 - 399 0
+ r* f( N# c$ R
Warnings 400 – 699 1400 – 1699 2
Informational 700 – 899 1700 – 1899 3
! ]7 F, X+ {! r6 C
Elective Notes 900 - 999 1900 - 1999 4
* K8 z) D9 F' s- ?3 @# T
6 e0 ?9 C7 d0 m0 n$ |
/ E1 I& J, b V' x+ t; w. [
错误信息禁止选项说明
$ t$ u7 e! w4 D# [7 u$ s
命令格式 说明 代码中的举例
+ U! Y2 J: b: l, X' v# q6 c
-e# 隐藏某类错误 /*lint -e725 */
9 V0 q/ _3 | _: L Y8 Z
-e(#) 隐藏下一表达式中的某类错误 /*lint –e(534) */
printf(“it’s all”);
!e# 隐藏本行中的错误 /*lint !e534*/ printf(“it’s all”);
( e. u/ V" /0 G$ l$ t1 |
-esym(#, Symbol) 隐藏有关某符号的错误 /*lint –esym(534, printf)*/
3 U/ /( n& E0 V3 t& N
printf(“it’s all”);
, Z, D: J/ z2 P7 a+ m
-elib(#) 隐藏头文件中的某类错误 /*lint –elib(129) */
2 U- ~! c9 _" E& m; @. |
#include “r01.h”
-efunc(#, ) 隐藏某个函数中的特定错误 /*lint –efunc(534, mchRelAll)*/
unsigned int mchRelAll(mchHoData
*pHoData)
4 c; @1 q; x, A B8 c8 v9 w1 b2 r
{
printf(“it’s all”);
+ V: b3 n2 l' J0 `# N/ K
}
@ k( C6 A. g5 y$ o# R
PC-Lint检测中的常见错误
8 w# c3 g/ `5 n# l8 q3 l: z2 y
错误编码 错误说明 举例
40 变量未声明
506 固定的Boolean值 char c=3;
if(c<300){}
4 I" j$ V& w8 }% |2 f) x
525 缩排格式错误
, m/ K- t6 |; l& L- j) g
527 无法执行到的语句 if(a > B)
1 T; Z- r- N& d( n
return TRUE;
$ C2 N" [1 N! /# j1 g" [2 U4 `
else
6 U0 s: Y- t p v6 f, h8 e
return FALSE;
9 i! ^" g; _, I* n- v$ F- [$ b
return FALSE;
, o! O3 [: I- z
529 变量未引用检查变量未引用的原因
$ w: {; C9 ~2 c b: H
530 使用未初始化的变量
534 忽略函数返回值
539 缩排格式错误
6 s2 y4 D1 H, P4 e% {
545 对数组变量使用& char arr[100], *p;
8 U7 r" {/ u# G, A) R$ n5 n$ ]; ^
p=&arr;
603 指针未初始化 void print_str(const char *p);
9 j, o* {3 c0 w
…
char *sz;
print_str(sz);
605 指针能力增强 void write_str(char *lpsz);
…
write_str(“string”);
/ X4 h; T4 j! j
613 可能使用了空指针
616 在switch语句中未使用 break;
2 o; i1 k# K# L
650 比较数值时,常量的范围超过了 if( ch == 0xFF ) ...
变量范围
" {/ M; M6 G, Z- }
713 把有符号型数值赋给了无符号型
数值
1 ]% F& T$ k' K9 t
715 变量未引用
1 u' Y( ^1 E9 F* /9 u
725 Indentation错误
; G& j% J. u: M( g
734 在赋值时发生变量越界 int a, b, c;
…
c=a*b;
0 V: x8 r, x) S! v0 n3 U; J; @/ e1 D7 S
737 无符号型变/常量和有变量型
变/常量存在于同一个表达式中。
744 在switch语句中没有default
752 本地声明的函数未被使用
762 函数重复声明
774 Boolean表达式始终返回真/假 char c; if(c < 300)
3. 源代码的静态检测工具Its4
3.1 its4 的相关介绍
% a2 p: R) t8 w: p3 s6 ^% G7 D
ITS4: Software Security Tool
Cigital developed ITS4 to help automate source code review for security. ITS4 is a simple tool that statically scans C and C++ source code for potential security vulnerabilities. It is a command-line tool that works across Unix and Windows platforms.
. V }# X- @. d) G
ITS4 scans source code, looking for function calls that are potentially dangerous. For some calls, ITS4 tries to perform some code analysis to determine how risky the call is. In each case, ITS4 provides a problem report, including a short description of the potential problem and suggestions on how to fix the code.
ITS4 and its source code are provided here to the security community for any use that does not compete with Cigital's consulting practice.
4 t# N. r4 d M q- F( v$ /
4 o1 o( @4 |7 }2 t* o! A
3.2 怎么安装ITS4
+ K8 {" M+ q3 q; J- s( X
ITS4 同其他windows 平台上的软件不同,它没有可执行的安装文件,从网站上下载下来的全部是ITS4的源代码(因此它的归属公司声称它为自由软件),所以必须编译和链接这些源文件,不过不用怕,它还给我们提供了一个名 MAKEFILE 的文件,在windows环境下,我们只要在使用nmakefile –f MAKEFILE 就可以生成一个可执行文件its4.exe。
. I4 }5 ]% B% f7 L X' F5 U
8 t w% h: r! ]8 O, V m: O
3.3 在命令行方式下使用ITS4
完成之后,如果你的当前目录不是 C:/its4/,那么你在除ITS4存放目录之外的其他目录下不能执行 its4 命令的(即使你已经设置过了环境变量),因为在执行这个命令的过程中,它会在C:/its4/下搜索一个名为vulns.v4d 的文件,如果失败,则这个命令就不能被正常执行。所以将编译后的整个its4目录复制到C盘生成C:/its4/.
这样你就可以正常执行了 its4 命令了。如果你嫌输入its4 命令的目录太长,你可以将C:/its设置为环境变量,这样你就可以在任意目录下 执行这个命令来检测你的源代码了。
3 i9 s# d" j/ S- j. _! z
3.4 在编辑器和编译器环境下使用ITS4
由于将its4 添加为编辑器和编译器的操作同PC_Lint差不多,所以这里就不罗嗦了。但要提醒的是,一定要注意配置Visual Studio 6.0 和 Visual Studio 8.0 时,参数项和初始目录有所不同,前者为 $(FileName)$(FileExt)/ $(FileDir)后者为$(ItemFileName)$(ItemFileExt)/ $(ItemDir)
0 P% r. q# f1 `2 J# b" ?
4. 怎样的代码算是安全的代码
, l3 e, o2 j3 X& U5 i
H3 G- z1 T" k0 q$ Q
4.1. 尽量少使用(或不使用)存在严重安全的C语言库函数
& m9 |. |7 ]' q4 m$ g& x1 l
由于C 语言自身的支持库存在本质上的安全隐患,由此引发出C 程序设计中存在多方面的安全问题。如下面的这些可能引发缓冲区溢出错误的函数:
; R" ^& S8 ^" D2 t* /
Strcpy() strcat() printf() scanf() gets() put() ……
' E# B8 e. s( F- Y! h" A
7 L' n5 Y: W: @6 W7 W8 D
在使用到这些函数的时候,我们应该尽量找其他一些更安全的函数来替换,如下:
6 z5 j }) U Y
Strncpy() strncat() fscanf(stdin, "%255s", buffer)……
, X8 R# d5 `" S
下面的例子演示了怎样安全的写代码:
, M( h; b8 m" [5 u/ C# o
不正确情况 正确的情况
5 g$ X9 H1 d) c$ [' C4 /8 S
void func(char *str) void func(char *str)
{ {
char buffer[256]; char buffer[256];
gets(buffer, str); fgets(buffer, sizeof(buffer) –1,stdin);
. p8 U( e$ ~( K% v
return; return;
} }
5. 我们应该怎样来写安全的代码
- J" a/ I J! E+ R
! d3 y" Z4 V5 H9 o
5.1. 按照如下书中所诉说的标准和规范:
/ }0 g( `5 P, ]9 @
; C* Q6 V8 G; P. K
《More Effective C++》、《C++编程规范》
5.2.遵循行业行规
& L4 x* r4 R- @& E0 m9 a: k
我的建议是遵循行业行规,严格按照规范写程序6. 用PC_Lint 、ITS4分别检测源代码示例
, s! d* b' f* ?. r# e
下面是一个用ITS4检测一个名为a.cpp源文件时的报告:
源代码:
$ o* q1 f0 b! A _! /% K1 @7 h( l
#include
% K/ f- B; ^% Z) i: H6 y m
void main()
{
printf("Hello Makefile!");
char ch[50];
gets(ch,stdin);
scanf("%c",ch);
% ~. p% r8 @) d
}
7 T5 c2 R# a$ @% K$ J: F4 C2 D
( Q/ R+ o! Z8 l( b* r0 |: y0 x
) f& C0 b7 m9 |: U3 d
检测报告:
! _/ c# G4 W& G$ ?8 h! ?
a.cpp:7:(Urgent) gets
# c; w) O8 g& M; `2 O
The input buffer can almost always be overflowed.
: f0 c9 S) J- N4 a: R; w
Use fgets(buf,size,stdin) instead.
/ { M* W1 @9 s' E3 e3 |
----------------
a.cpp:5:(Urgent) printf
1 U: M m; O) p
Non-constant format strings can often be attacked.
Use a constant format string.
$ t2 _; d" x0 ~' o
----------------
/ X" e5 m8 o# p8 i2 o. g* R
9 W$ {2 L' i- {5 }
5 ~. B! _' F. a( D6 y% r6 F; P* k
下面是一个用PC_Lint检测一个名为testpc.cpp源文件时的报告:
8 /3 q; W7 `, w0 s6 e6 p; Y
; }9 X! J0 I4 Q+ i
源代码:
9 R/ z: |) |; B/ @9 Z! ^
#include
using namespace std;
int main()
{
int*fo;
+ h9 H% Z& q3 E2 W8 ?- t2 D- B
fo[1] = 3;
fo = new int(10);
for (int i = 5 ; i < 15 ; i++ )
4 G" e* T6 p' k t9 y/ D- q1 O
{
/ h; R! h8 h2 _/ T5 o4 j5 C& V% Q4 p
fo
= i;
cout<<"fo["<
: w6 @+ U, o. h
检测报告:
1 int main()
2 ……………… r9 u2 Z) j- d) O |
3 int*fo;
4 testpc.cpp(5) : Note 970: Use of modifier or type 'int' outside of a typedef ' {, @4 x3 b0 l: O2 Q r1 V3 p
5 [MISRA Rule 13] ' F/ Z% {9 M3 |, c) H& ?
6 _
7 fo[1] = 3;
8 testpc.cpp(7) : Warning 530: Symbol 'fo' (line 5) not initialized [MISRA Rule
9 30]
10 ………………… ^. R3 O6 W) Z, y* p0 o4 R
11 _
12 fo = new int(10); 9 a" ^( ]1 G8 J8 N1 D/ { Y
13 testpc.cpp(9) : Note 970: Use of modifier or type 'int' outside of a typedef & k5 m7 ? L2 n, k
14 [MISRA Rule 13] 5 _. F( e& ^7 X5 H* D- w: p2 X7 E
15 testpc.cpp(9) : Warning 1556: 'new Type(integer)' is suspicious 4 E) h: b; I/ `' c5 m4 ~
16 _
17 for (int i = 5 ; i < 15 ; i++ )
18 testpc.cpp(12) : Note 970: Use of modifier or type 'int' outside of a typedef : }. c* ]/ a) F* I* Y* n% V. v2 o
19 [MISRA Rule 13]
20 …………………
21 _
22 fo = i;
23 testpc.cpp(14) : Warning 662: Possible creation of out-of-bounds pointer (5 7 T# u& e- p3 d" O2 ?$ Q
24 beyond end of data) by operator '[' [Reference: file testpc.cpp: lines 9, 3 c' G Y8 K# v8 I3 ]2 ^
25 12, 14]
26 ………………… ' P" y3 G# F: t0 u+ Z
27 _ 0 b; c% R0 A/ n k6 w/ K( U
28 cout<<"fo["<<29 testpc.cpp(15) : Warning 662: Possible creation of out-of-bounds pointer (5 3 |) T& S( Z# H, ]/ B" ]
30 beyond end of data) by operator '[' [Reference: file testpc.cpp: lines 9, 9 u3 A E: f' R* D0 E. W* L/ O: i
31 12, 15]
32 …………………
33 _
34 return 0; ) p9 y, ~$ Z% ^5 d% l
35 testpc.cpp(17) : Warning 429: Custodial pointer 'fo' (line 5) has not been & W& n" j% Y+ A ]$ o
36 freed or returned 7 // W0 P: k" I7 l4 d! _
37
0 `; P, a: f/ G2 s$ O+ [
报告分析:
0 L3 n. N' H* i9 p' t2 |; N1 ]3 {3 P
在这份报告中,PC_Lint检测出了许多Visual Studio 8.0 不能检测出的潜在问题,如:
( E- d5 ^5 x5 b, G# m) o" k4 ^
在上面的第8行报告使用了为初始化的变量fo;* b! o/ m! C6 b/ d( /0 o9 G
在上面的第23、29行报告使用的指针索引可能越界了;$ I, W" W& k! m/ P5 b! /
% V$ I& ?0 x0 N2 i( ?( H% B9 L* D0 V
在上面的第35行报告程序中动态申请的空间没有释放。