软件静态分析工具评析
2011-04-24孔祥营
王 凯,孔祥营,2
(1.江苏自动化研究所,江苏 连云港 222006;2.南京航空航天大学,江苏 南京 210016)
随着软件规模越发庞大,其包含的bug也越来越多,再加上软件文档不齐全,严重影响了软件的质量。为了提高软件质量,需要进行软件测试。软件测试是保证软件可靠性的重要手段,其目的是尽可能多地暴露软件中潜在的各种错误。
软件测试从是否运行被测软件角度分为静态测试和动态测试。静态测试指在不运行被测软件情况下用于发现软件缺陷所进行的测试,包括人工进行的代码检查、文档审查和软件静态分析。动态测试是指通过运行被测软件来检验软件的动态行为和运行结果的正确性。软件静态分析是在不执行程序的情况下对源代码进行控制流、数据流、接口和表达式进行分析。软件静态分析是软件测试的有效方法之一。研究表明:“bug发现的越晚,修正的成本就越高,即测试阶段修正bug的成本是编码阶段的约4倍”[1],另一方面,“程序中的大部分错误往往是在一小部分模块中发现的,遵循普遍适用的“二八定理”(即 80%的错误往往是由20%的程序模块引起的)”[2]。在软件生命周期的编码阶段,由于可运行的代码尚未产生,不可能进行动态测试,但可以实施软件静态分析来确认和标识这20%程序模块,由此可见,软件静态分析的作用在编码阶段尤为重要。本文对动态测试不做进一步阐述,重点讨论静态测试的软件静态分析。
实施软件静态分析的最有效手段是使用静态分析工具。C语言设计初衷主要是出于效率和灵活性两方面考虑,灵活性带来代码效率的提高,但相应带来代码编写的随意性,另外C编译器不进行强制类型检查,也带来代码编写的隐患。例如,C语言不对数组读写访问越界进行检查。因此需要借助软件静态分析工具对被测程序源代码实施软件静态分析来加强C程序缺陷检查。本文首先对C程序包含的主要软件缺陷进行说明。
1 软件缺陷
C程序的软件缺陷主要有:空指针引用、悬空指针、资源泄露、函数返回值、使用未初始化变量、无限循环、死亡代码、缓冲区溢出、野指针等。下面对这些缺陷及其原因进行简要描述。
1)空指针引用[3]
空指针引用会导致程序崩溃。空指针引用的情况包括:
①忘记对指针为NULL的情况进行判断;
②虽然对指针是否为NULL进行了判断,但没能正确处理好。
2)缓冲区溢出[3]
缓冲区溢出是最常见的安全漏洞,包括静态溢出和动态溢出。静态溢出主要指数组或指针的索引为常量情况下的越界,导致内存冲突,给黑客攻击提供了可乘之机,主要包括栈溢出、堆溢出、数据段溢出、BSS溢出和共享内存溢出;动态溢出主要是数组或指针的索引在动态访问内存的时候越界,由于C语言固有的不安全性,数组或指针的索引不会自动去做边界检查,因此缓冲区溢出的情况非常普遍,所以程序员在用C语言编写代码时有必要检查索引是否在有效区间内,但在复杂的函数调用和数据流传递中,这项工作变得异常复杂。
3)悬空指针[4]
悬空指针是由于使用了已经释放的内存资源造成的。引用已释放的指针是非常危险的,因为指针的值不确定或者指针指向任意内存的位置。为了避免悬空指针,必须在最后的引用释放后再删除对象。
4)资源泄漏[5]
资源泄漏是程序离开了指针的作用域后,仍没有释放指针占用的资源造成的。资源泄漏包括内存泄漏、文件句柄泄漏和网络套接字泄漏。
严重的内存泄漏能导致进程崩溃,即便是很小的内存泄漏,在系统长时间运行没有重启后,也会产生错误。文件句柄或者网络套接字的泄漏会导致程序崩溃、拒绝服务攻击或者打开其他文件或套接字失败。操作系统通常会限制进程的文件句柄和套接字个数。当达到限制的最大值时,进程要申请新的资源时,首先要关闭一些已打开的资源。如果进程中存在资源泄漏,进程自己将没有办法回收这些资源,除非强行终止该进程。
多数情况下,这些泄漏通常发生在某个错误的路径,比如说,某个异常处理的分支。这种情况下,正确的做法应该是将程序跳转到该函数的出口,出口处应释放这些资源。
5)函数返回值
函数返回值错误主要包括函数遗漏返回值和函数返回值可能为空或为局部变量的地址或为负整数。函数返回值使用前,一定对其值进行判断。如果为空,对其非法引用将会导致程序崩溃;如果为负整数,在作为数组索引、循环标志变量、申请内存大小的参数等情况下要检查函数返回值的正确性,负整数的错误使用会导致如死循环、数组越界(内存冲突)、变量溢出等严重的问题;如果是局部变量的地址,在C语言中,当被调用函数执行完毕,其所有的局部变量就不再有效,因此将会引起内存冲突和不确定的行为;在返回类型为非void的函数中,值没有被返回,比较常见的情况是,在不同的分支要返回不同的值,结果有一个分支漏了返回值。
6)使用未初始化变量
变量在使用前没有初始化。堆栈中的变量如果没有初始化,将没有固定的数值。使用了没有初始化的变量会导致不可预测的行为,或安全漏洞。
7)无限循环
程序中有不能终止的循环,会导致程序挂起或者崩溃。当然在多任务的程序中,故意设计的“死循环”除外。
8)不可达代码
由于条件判断总是TRUE或FALSE,导致一个分支内的代码永远执行不到,这些永远都执行不到的代码称为不可达代码。不可达代码一般是由逻辑错误引起的。在情况严重时,这些逻辑错误可能导致重要的代码永远不能执行,造成严重的后果。
9)野指针[6]
野指针不是NULL指针,是指向“垃圾”内存的指针。产生野指针主要有两个方面的原因:
①指针变量未被初始化。任何指针刚创建时不会自动成为NNLL指针,而是随机的,它会乱指一气。故指针创建时应当初始化,要么将指针设置为NULL,要么让它指向合法的内存。
②指针p被free或delete后,没有设置为NULL。这样让人误以为p是合法的指针,其实free或delete仅把p所指向的内存释放掉,但并没把指针p本身释放(仍指向原来的地址)。通常用 if(p!=NULL)进行防错处理,但是很遗憾,此if语句根本起不到防错的作用,因为即使p不是NULL,它也不指向合法的内存块。
另外不要将指针或引用指向栈内存,因为栈内存在函数结束时会被释放。
针对C程序的软件缺陷,人们设计了很多软件静态分析工具。目前问世的静态分析工具能否有效发现这些软件缺陷,需要我们对软件静态分析工具作进一步研究。
2 软件静态分析工具
软件静态分析工具不仅可以查找源代码中缺陷,也可以用来发现与大规模代码库交互过程中产生的缺陷。构建静态分析工具采用一定的算法,即静态分析技术[7-9],主要包括符号执行、定理证明、类型推导、基于规则的检查、模型检测、分析工具中使用的规约、词法分析、语法分析、污点传播、布尔可满足性、整数范围分析、基于调用图/控制流图分析、基于程序注释和增式分析等。其工作原理是通过算法检查代码的错误,并标明问题区域,以便编程人员做更详细的检查,这种算法方式无需使用测试用例,算法本身决定了静态分析工具发现错误的效率。
静态分析技术和静态分析工具二者是相辅相成,互相促进。随着人们对软件质量要求越来越高,静态分析技术不断出现,同时伴随着软件静态分析工具的问世。通过对软件静态分析工具的应用研究,软件静态分析工具存在的缺陷与不足逐渐暴露出来,又促使人们不断改进现有的和提出新的静态分析技术。
目前可供选择的静态分析工具很多,主要包括Klocwork K7[8]、FlawFinder[9]、BOON[9]、MOPS[10]、Coverity Prevent[10]、Splint[11]、PolySpace Verifier[13-14]等。合适的静态分析工具将大大提高静态分析效率,因此如何选择静态分析工具非常关键。选择静态分析工具需要权衡的因素主要包括:静态分析工具的误报率和bug率[14-15]、支持的编程语言、性价比、易于安装和使用、使用静态分析工具的时机和频率等。以PolySpace Verifier、Splint、Klocwork K7、Coverity Prevent为代表的静态分析工具正将工具的作用向软件生命周期的早期阶段推进,促进了静态分析的发展。下面对主流静态分析工具进行简要介绍:
1)PolySpace Verifier
PolySpace Verifier是由PolySpace公司开发的商业静态分析工具,用于发现运行时 bug。已经在嵌入式系统相关领域得到广泛使用,如自动化、航空航天、国防部和铁路交通等领域。当进行静态分析时,PolySpace能识别算术异常、数组索引越界、未初始化局部变量、指针无效解除引用、无效类型转换、缓冲区溢出、未保护共享数据以及不可达代码等bug。
PolySpace Verifier将以橙色标识大量代码表示代码可能包含一个缺陷,绿色标识的代码表示代码没有缺陷,红色标识代码表示的确是缺陷,而灰色标识代码表示死亡代码(即无法执行的代码)。
2)Splint
Splint是开源的静态分析工具,用于检测用标准C实现的软件缺陷,通过在源代码中添加关于函数、变量、参数和类型的格式化注释,实现了未使用的声明、类型不一致性、使用未定义变量、内存泄漏、不可达代码、函数返回值、无限循环、危险的别名等软件缺陷。
3)Klocwork K7
Klocwork K7是商业静态分析工具,目前最新版本为Klocwork Insight。支持C/C++/Java,也是宣称能处理 C/C++/Java三种语言写的复合应用程序的唯一提供商。Klocwork K7能识别内存泄露、缓冲区溢出、使用未初始化变量、函数返回值等软件缺陷。
4)Coverity Prevent
Coverity Prevent是一款商业静态分析工具,支持C/C++/Java。Coverity支持整个系统的增式分析,在上次分析的基础上仅仅有部分代码被修改。分析的结果被保存并在接下来的分析中重用。这样的增式分析比分析整个系统所花时间明显要少很多。Coverity Prevent能识别死锁、资源泄露、空指针引用、悬空指针、不可达代码、未初始化变量、函数返回值、缓冲区溢出等软件缺陷。
通过 PolySpace Verifier、Splint、Klocwork K7和Coverity Prevent对应用程序静态分析,结果见表1。
由以上分析结果知道:尽管静态分析工具在揭露软件缺陷方面发挥着重要作用,但静态分析工具并不是完美的,PolySpace Verifier、Splint、Klocwork K7和 Coverity Prevent采用算法的片面性决定了它们都只能发现部分缺陷。为了保证软件测试的质量和有效性,我们认为软件静态分析工具在查找软件缺陷方面是行之有效的,但也要认识到软件静态分析工具存在的不足之处。
静态分析工具优点包括[15]:
①开发早期发现软件错误,易于修改,降低开发成本;
②防止错误在系统中扩散进而影响后期开发的代码行为;
③有助于开发人员发现个人编码风格的缺点。
静态分析工具缺点包括[15]:
①存在误报和漏报的可能性,降低静态分析有效性;
②输出结果仍然需要人工确认,增加开发成本;
③采用算法的片面性,使得静态分析不能解决所有安全问题。
表1 主流静态分析工具比较
3 结束语
软件静态分析工具可以在软件生命周期的编码阶段实施测试,有助于降低软件成本和开发时间,随着软件静态分析工具功能越来越强大,逐渐受到开发人员和测试人员重视和喜爱。但静态分析工具存在较高漏报率和误报率,降低了测试的有效性,另外静态分析工具无法暴露一些运行时错误,因此仅采用静态分析还不够,需要在软件生命周期的晚期阶段进一步实施动态分析,可以说静态分析是对动态分析的有效补充,使软件测试更加高效。针对软件静态分析工具优势与不足并存及种类繁多的现状,要选择适合自己的工具,需要对影响软件静态分析工具选择的诸多因素综合权衡。
[1]huior.我看“静态测试”[EB/OL].http://www.51testing.C om/?10851/action_viewspace_itemid_72777.html.2008-0 1-16.
[2]于波,姜艳.同行评审[EB/OL].http://www.uml.org.cn/rjzl/200902024.asp.2009-02-02.
[3]余建军,韩双霞,黄云龙.软件安全性的静态分析[J].计算机工程与设计,2006,27(8):1411-1414.
[4]ruanruan111.内存出错,内存泄露,数据越界,悬空指针,错误分配[EB10L].
[5]肖庆,张威,宫云战,等.内存泄漏的一种静态分析方法[J].装甲兵工程学院学报,2004,18(2):23-26.
[6]xserver.杜绝野指针[EB/OL].http://www.javaeye.com/wiki/topic/625904.2010-03-27.
[7]杨宇,张健.程序静态分析技术与工具[J].计算机科学2004,31(2):171-174.
[8]夏一民,罗军,张民选.基于静态分析的安全漏洞检测技术研究[J].计算机科学,2006,33(10):279-282.
[9]shiliyanfir.klocwork介绍[EB/OL].http://www.docin.com/p-8466186.html.
[10]Lauri Kolmonen.Securing Network Software using Static Analysis[J].TKK T-110.5290 Seminar on Network Security 2007-10-11/12.
[11]jack2000ran.软件错误及安全性检测工具.Coverity Prevent[EB/OL].2009-02-20.
[12]sciyon_2010.Splint Manual[EB/OL].http://wenku.baidu.com/view/f2a7c50c6c85ec3a87c2c59d.html.2011-01-24.
[13]Par Emanuelsson and Ulf Nilsson.A Comparative Study of Industrial Static Analysis Tools[J.Electronic Notes in Theoretical Computer Science 217 (2008)5–21.
[14]DING Zhigang,WANG Hongcheng,LING Lianghe.Practical Strategies to Improve Test Efficiency[J].TSINGHUA SCIENCE AND TECHNOLOGY,2007,12(S1):250-254.
[15]Paul E.Black,Michael Kass,Michael Koo.Source Code Security Analysis Tool Functional Specification Version 1.0[J.NIST SP 500-268 May 2007:1-14.
[16]郑人杰.计算机软件测试技术[M].北京:清华大学出版社,1997..