缺陷查找自动化——快速找出潜在的软件缺陷
from: http://www.neco.com.cn/DRNECO/Content_003/automate%20code%20review.htm
缺陷查找自动化——快速找出潜在的软件缺陷
Kevin Smith
刚刚提交了几百万行复杂的C++代码吧?啊,祝贺你!这些代码可能是一个内部开发的产品,也可能是商业C++库,或者是一些从网上下载的要加入到下一个产品版本中的开源代码。虽然测试结果说明,软件基本上能够工作了,但是你还是担心其中会隐藏大量的潜在缺陷(latent defect)。那么,应该如何在产品发布日期之前把它们找出来呢?本文我将介绍一种无需进行昂贵的测试或者仿真就能快速地找到潜在缺陷的技术。当然,这种技术是普通测试工作的一种补充。我最近就使用它们很快发现和修正了一个软件系统中的几千个缺陷,要知道这个系统含有几百万行C++代码,非常复杂。
潜在缺陷
所谓潜在缺陷,就是指软件中存在但是又无法通过常规测试过程发现的缺陷。例如,在一个非常大的软件系统中,不可能测试源代码中所有可能的执行路径(在一个大型软件系统中,要覆盖条件分支的所有组合,可能需要数十亿计的测试用例)。有些没有测试的执行路径可能包含着严重的编程错误。其中的挑战在于,如何在客户发现它们之前找到这些潜在缺陷。我曾经发现的缺陷中大部分都位于前面的测试周期中没有正确覆盖的各种错误路径。显然,在设计阶段尽早地改正缺陷,即省时又小钱,因此在软件大批出货之前发现尽可能多的缺陷是至关重要的。我把我找到的潜在缺陷分成八大类:
·指针/数组违例 比如析取(dereference)空指针、访问数组维度之外的数组元素、复制内存或者字符串到过小的缓冲区中。
·变量未初始化 在用值对变量进行初始之前就使用它,或者在删除指针以后还析取其指针。
·非法返回值 从非void函数返回void值,或者返回一个指向局部变量的指针。
·内存泄漏 退出一个过程(可能是通过错误的路径退出的)时,没有释放分配的内存以及保存在局部变量中的内存,这在过程有多个退出点时经常发生。
·常见的C语言错误 在if语句后加上了“;”;在if语句中使用了“=”而不是“==”;操作符优先级错误,或者case语句块中少了break。
·常见的C++错误 在需要使用delete[]时却使用了delete;在对象的构造函数中调用虚函数,或者应该有复制构造函数时却没有提供。
·整数大小错误 将一个16位整数移位24位,用32位值初始化16位整数变量。
·逻辑错误 算法实现错误或者不完整。
静态代码分析
静态源代码分析工具能够查看我们的源代码,寻找bug,有点类似于自动化的代码审查。Lint是针对C语言软件最古老也最有价值的静态源代码分析工具。这里主要的困难是lint会产生大量输出,而其中只有一小部分反映了真正的错误。为了避免大海捞针之苦,我买了Gimpel 软件公司(http://www.gimpel.com/lintinfo.htm)的Flexelint,因为这种版本的lint能禁止特定的警告,而且可以很好地处理C++源代码。在几个星期的实验之后,我得出一组lint规则,可以得到极佳的信噪比。按这种方式运行lint,很快得到了1843个缺陷。第一个lint配置文件给出了能很好地找到真正缺陷的lint规则列表。
这个配置文件的目的是通过找到常见的C++编码错误、潜在的内存泄漏和常见的编码规范违协同作战,来帮助人工的代码审查。第二个lint配置文件是前一个文件的子集。这个文件检查那些明显的和严重的错误,能够对提交给源代码库的任何代码进行清晰的处理。这些配置文件并没有使用lint的完整功能,因为为了生成高信噪比的输出,有些合法的错误被忽略了。这项技术的工作原理,是要求lint禁止所有的警告,然后打开选中的几个。
我还推荐对软件中所有第三方的源代码用lint进行审查(除非你愿意自己的声誉寄托在别人的源代码上)。有许多商业产品能够对C++源代码进行静态分析。有一些优秀的工具(比如Splint)能很好的处理C语言代码,而且是免费的。表1中列出了一引起常见的静态分析工具,其中大多数工具都贯彻了Scott Meyers在《Effective C++》系列图书和光盘中发表的C++编程规则[也可能参见Scott Meyers在DJJ 1997年2月发表的文章“Examining C++ Program Analyzers(C++程序分析工具考察)”]。
表1 常见的静态分析工具
产品 | 供应商 | 代码复杂度 | 静态分析
Code | Wzard Parasoft(http://www.parasoft.com/poducts/wizard/index.htm | No | Yes
Rexelint | Gimpel Software(http://www.gimpel.com/lintinfo.htm) | No | Yes
Splint | University of Virginia(http://www.splint.org) | No | Yes
Logiscope | Telelogic(http://www.telelogc.com/products/tau/logiscope/index.cfm) | Yes | Yes
QA C/C++ | QA Systems(http://www.qa-systems.com/products/qac/ | Yes | Yes
Mc Cabe QA | McCabe & Associates(http://www.mccabe.com/main.htm) | Yes | Yes
Understand C++ | Scientific Toolwarks(http://www.scitools.com) | Yes | No
CodeCheck | Abraxas(http://abxsoft.com) | Yes | Yes
GateKeeper | KLOOwork(http://www.klocwork.com/) | Yes | Yes
下一步
收集了软件中子系统的信息后,要特别注意哪些子系统中包含了严重的编译警告或者大量严重的lint错误。这些数据可能指出了整个软件组织中存在的一些潜在问题,例如,我们的人员配备和C++培训水平是否适用于系统的复杂性?每个子系统中出现这么多缺陷是否正常?也许,应该决定更换第三方软件库的供应商了。
结语
这项技术都能有效地找出软件中的潜在缺陷,而且能够以较少的成本很快实现。如果时间紧迫,只能采用其中一项的话,我推荐进行最短时间内的最大效益。但是,对于大型软件系统而言,在每个版本发布之前不使用所有这项技术是不可理喻的。虽然这些缺陷辨识技术从根本上说不是新东西,但是你敢说自己不会从这种有的放矢的分析中获益?