多年前,静态代码分析最大的挑战是试图找到更多更有趣的东西来检查。在90年代初Parasoft最初的CodeWizard产品中,有了根据Scott Meyers的《Effective C++》一书中的项目制定的30多条规则。我喜欢把它看做是“程序员的直觉”。我曾经跟Scott提到过这件事,虽然他没有这样想过......但这确实让他笑得很开心。程序员
从那时起,静态分析研究人员就不断努力推进能够检测的范围,扩大静态分析的范围,识别缺陷而不只仅是一段弱代码。但它仍然存在误报的问题。静态分析改变了用户的关注点,从硬化代码,到搜索bug,这是很好的,但如今人们在静态代码分析中遇到的最多见的障碍之一是试图理解他们获得的结果。编程
虽然人们确实会说“我但愿静态分析能抓住____”(说出你最喜欢的找不到的bug),但更常见的是听到“哇,个人结果太多了!”或“静态分析太吵了!”或“静态分析的误报太多!”所以,做为一家软件测试机构,Parasoft的工做就是继续为客户解决这个问题——继续提供工具和功能,帮助你梳理获得的结果,并了解哪些问题表明了最大的风险。安全
在静态分析中,当静态分析工具错误地报告违反了静态分析规则时,就会出现“误报”。固然,这多是主观的。有时,开发人员会掉进一个陷阱,把任何他们不喜欢的错误信息都贴上“误报”的标签,但这其实并不正确。在不少状况下,他们只是不一样意这个规则,他们不理解这个规则在这种状况下是如何应用的,或者他们认为它在通常状况下(或者在这个特殊状况下)并不重要。我把这叫作噪音,而不是误报。我在这里发现的有趣的事情是,工具越是聪明,就越有可能产生一个开发者乍一看可能不理解的发现。工具
基于模式的静态分析实际上并不存在误报。若是工具报告说某条静态分析规则被违反了,而实际上并无,这说明规则有bug(由于规则不该该是模棱两可的)。若是规则没有明确的模式可寻,这就是一个坏规则。单元测试
我并非说每个被报告的规则违规都表示存在缺陷。违规只是意味着发现了模式,代表代码的弱点,容易有缺陷。测试
当我看到一个违规行为时,我会问本身这个规则是否适用于个人代码。若是适用,我就修复代码。若是不适用,我就抑制这个违规行为。最好直接在代码中压制静态分析违规行为,这样对团队成员来讲是可见的,并且你最终也不会再去审查第二次。不然,你就会不断地重复审查一样的违规行为;这就像试图拼写检查,但永远不会在它的字典中添加你的“特殊”单词同样。代码内抑制的好处是,它独立于静态分析引擎。任何人均可以查看代码,并看到代码已经被审查过,而且这个模式被认为在这个代码中是能够接受的。若是你须要证实符合编码标准,这一点特别有用。而若是你确实须要符合标准,那么很容易使用现有的配置来知足这些标准,如CWE、MISRA、IEC 62304、DO-178B/C等。编码
对于基于流程的分析,误报不只是方法所固有的,并且是相关的--须要解决。流程分析没法避免误报,缘由与单元测试没法生成完美的单元测试用例同样。分析必须对代码的预期行为作出判断。有时选项太多,没法知道什么是现实的;有时你根本没有足够的信息来了解系统其余部分的状况。spa
这里重要的是,真正的误报是彻底错误的东西。例如,假设你正在使用的静态分析工具说你正在读取一个空指针。若是你看了一下代码,发现这实际上是不可能的,那么你就有一个误报。线程
另外一方面,若是你根本不担忧这段代码中的空值,由于它们在其余地方被处理了,那么这个消息(虽然对你来讲并不重要)并非一个误报。它是真实的,并且刚好是不重要的。流程分析工具的消息从“真实且重要”到“真实且不重要”,从“真实且不可能”到“不真实”。这里有不少变化,每一个人都应该有不一样的处理方式。指针
这里也有一个常见的陷阱。就像上面的null例子同样,你可能认为一个null值不可能作到这一点,可是工具找到了一种方法让它发生。若是它对你的应用很重要,必定要检查,并可能对此进行保护。
关键是要明白,流分析有力量也有弱点。流程分析的强大之处在于,它经过代码,试图找到热点,并围绕热点发现问题。弱点是它必须作出假设来尝试遍历代码,并且越是遍历,越容易产生不可能的路径。
真正的问题是,若是你开始认为你已经清理了全部的代码,由于你的流程分析是干净的,你是在欺骗本身。真的,你已经发现了一些错误,你应该为此感到庆幸。没有流程分析错误只是意味着你没有发现任何东西,而不是说代码很干净。若是你正在构建安全关键型软件,最好确保你使用的是C/C++test、dotTEST或Jtest这样的工具,它同时具备两种类型的静态分析功能。
一个很好的,但一般被忽视的补充流分析的方法是运行时错误检测。运行时错误检测能够帮助你发现比流程分析能检测到的更复杂的问题,并且你有信心该条件确实发生了。运行时错误检测不会像静态分析那样出现误报。当它发现一个缺陷时,是由于它在执行过程当中实际观察到了它的发生——不涉及任何假设。
你的运行时规则集应该与静态分析规则集紧密匹配。这些规则能够发现相同类型的问题,但运行时分析有大量的执行路径可供它使用。这是由于在运行时,存根、设置、初始化等都不像流分析那样成为问题。惟一的限制是,它只和你的测试套件同样好,由于它检查你的测试套件刚好执行的路径。若是你是用C或C++编程,特别是像物联网这样的嵌入式设备,能够看看Insure++——它能够在运行时找到比其余任何工具更多的bug。而不是被线程问题、内存泄漏和竞赛条件等棘手的问题所困扰,你能够在运行时准确地找到它们。
我对待误报的方法是这样的。若是要花3天时间来修复一个bug,那还不如花20分钟去看一个误报......只要我能够标记它,永远不用再看它。这是个正确看待的问题。好比说你的线程有问题。线程的问题是急剧难以发现的。若是你想找到一个与线程有关的问题,你可能要花上几周的时间去追踪它。我更但愿在写代码的时候,首先不能出现问题。换句话说,我试图将个人过程从检测转向预防。
静态分析,若是部署得当,并不必定是一种嘈杂不愉快的体验。看看Parasoft是如何以不一样的方式作事的,特别是使用Parasoft DTP的所有功能,经过智能分析来管理结果,让你专一于软件中的风险,而不是追逐不重要的问题。