解析代码漏洞:FindBugs[网络技术]
本文“解析代码漏洞:FindBugs[网络技术]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
FindBugs 是什么? FindBugs 是一个静态解析工具,它查抄类大概 JAR 文件,将字节码与一组缺陷情势举行比较以发现大概的问题.有了静态解析工具,便可以在不实际运行程序的情形对软件举行解析.不是通过解析类文件的情势或构造来肯定程序的企图,而是普通利用 Visitor 情势(请参阅 参考资料).图 1 显示了解析一个匿名项目的后果(为避免可怕的犯罪,这里不给出它的名字): 在FindBugs的GUI中,需求先挑选待扫描的.class文件(FindBugs其实就是对编译后的class举行扫描,藉以发现一些躲藏的bug.).假如你拥有这些.class档对应的源文件,可把这些.java文件再选上,这样便可以从稍后得出的报告中快速的定位到出问题的代码上面.此外,还可以选上工程所利用的library,这样仿佛可以帮忙FindBugs做一些高阶的查抄,藉以发现一些更深层的bug. 选定了以上各项后,便可以开始检测了.检测的历程大概会花好几分钟,具体视工程的规模而定.检测完毕可生成一份具体的报告,藉由这份报告,可以发现很多代码中间潜在的bug.对比典型的,如引用了空指针(null pointer dereference), 特定的资源(db connection)未关闭,等等.假如用人工查抄的方法,这些bug大概很难才会被发现,大概永久也无法发现,直到运行时爆发…当撤除了这些典型的(classic) bug后,可以确信的是,我们的系统安定度将会上一个新的台阶. 以目前碰到的情况来看,FindBugs可以有两种利用机会. 开辟阶段 当Developer完成了某一部份功效模块开辟的时刻(这普通是指代码撰写完成,并已debug通过之后),可藉由FindBugs对该模块触及的java文件举行一次扫描,以发现一些不易发觉的bug或是效能问题.拜托新版的时刻,开辟团队可以跑一下FindBugs,撤除一些躲藏的Bug.FindBugs得出的报告可以作为该版本的一个参考文档一并拜托给测试团队留档待查. 在开辟阶段利用FindBugs,一方面开辟人员可以对新版的品质更有信心,另一方面,测试人员藉此可以把更多的精神放在业务逻辑的确认上面,而不是花大量精神去进一些要在特别情况下才大概呈现的BUG(典型的如Null Pointer Dereference).从而可以提高测试的效率. 保护阶段 这里指的是系统已经上线,却发现因为代码中的某一个bug招致系统崩溃.在撤除这个已表露的bug之后,为了快速的找出近似的但还未表露的 bug,可以利用FindBugs对该版的代码举行扫描.当然,在保护阶段利用FindBugs常常是无奈之举,且时间紧急.此外,假如本来在新版拜托的时刻就利用过FindBugs的话,常常意味着这种bug是FindBugs还无法检测出的.这也是FindBugs范围的地方. FindBugs出到目前的版本,功效已经相当强盛,不过也有待完善的地方.从实际利用来看,有一些躲藏的bug并不能靠FindBugs直接发现.那么,可不可以撰写一个新的 Detector,来发现这种将一个未初始化的reference传来传去而形成的潜在的bug呢?理论上来说,应当是可以的.这个 Detector目前还未实现.哪位假若有爱好的话,可以参考FindBugs, Part 2: Writing custom detectors(扩大阅读)这篇文章,帮忙实现这个Detector.实现一个新的Detector,便可以检测出一种新型的bug,这样不知又可以帮开辟人员省去多少人工查抄的时间,功德无量啊. FindBugs也不能发现非java的Bug.关于非java撰写的代码,如javascript,SQL等等,要找出此中大概的bug,FindBugs是无能为力的.当然,javascript中的bug仿佛还不至于使系统崩溃,而SQL中的bug常常又跟业务逻辑相关,只要测试细心一些应当是可以发现的. FindBugs不过是一个工具.作为开辟人员,当然首先要在编程的时刻勤奋避免引入bug,而不要依靠于某个工具来为自己把关.不过由于代码的复杂性,一些躲藏的bug确切很难靠咱们的肉眼发现.这时,利用一些好的工具大概便可以帮你发现这样的bug.这就是FingBug存在的代价. 为什么应当将 FindBugs 集成到编译历程中? 常常问到的第一个问题是为什么要将 FindBugs 加入到编译历程中?固然有大量来由,最明显的答复是要保证尽大概早地在举行编译时发现问题.当团队扩大,并且不可避免地在项目中加入更多新开辟人员时,FindBugs 可以作为一个安全网,检测出已经辨认的缺陷情势.我想重申在一篇 FindBugs 论文中表述的一些概念.假如让一定数目的开辟人员共同工作,那么在代码中就会呈现缺陷.像 FindBugs 这样的工具当然不会找出全部的缺陷,但是它们会帮忙找出此中的部份.目前找出部份比客户在今后找到它们要好——分外是当将 FindBugs 结合到编译历程中的本钱是如此低时. 一旦肯定了加入哪些过滤器和类,运行 FindBugs 就没什么本钱了,而带来的好处就是它会检测出新缺陷.假如编写特定于利用程序的检测器,则这个好处大概更大. 生成有意义的后果 重要的是要熟习到这种本钱/效益解析只有在不生成大量误检时才有效.换句话说,假如在每次编译时,不能简单地肯定能否引入了新的缺陷,那么这个工具的代价就会被抵消.解析越自动化越好.假如修复缺陷意味着必须吃力地解析检测出的大量不相关的缺陷,那么您就不会常常利用它,大概至少不会很好地利用它. 肯定不关心哪些问题并从编译中解除它们.也可以挑出 确切关注的一小部份检测器并只运行它们.另一种挑选是从个别的类中解除一组检测器,但是其他的类不解除.FindBugs 供应了利用过滤器的极大机动性,这可帮忙生成对团队有意义的后果,由此我们进入下一节. 肯定用 FindBugs 的后果做什么 大概看来很明显,但是您想不到我参与的团队中有多少加入了近似 FindBugs 这样的工具而没有真正操纵它.让我们更深化地探究这个问题——用后果做什么?明确答复这个问题是艰难的,因为这与团队的组织方法、若何处理代码全部权问题等有很大关系.不过,下面是一些指导: 可以考虑将 FindBugs 后果加入到源代码管理(SCM)系统中.普通的经验做法是不将编译工件(artifact)放到 SCM 系统中.不过,在这种特定情形下,冲破这个法则大概是精确的,因为它使您可以监督代码质量随时间的改变. 可以挑选将 XML 后果转换为可以发送到团队的网站上的 HTML 报告.转换可以用 XSL 款式表大概脚本实现.有关例子请查看 FindBugs 网站大概邮件列表(请参阅 参考资料). 像 FindBugs 这样的工具普通会成为用于敲打团队大概个人的政治武器.尽大概抵抗这种做法大概不让它发生——记着,它只是一个工具,它可以帮忙改良代码的质量.有了这种思惟,在下一部份中,我将展示若何编写自定义缺陷检测器. 问题发现的例子 下面的列表没有包含 FindBug 可以找到的 全部问题.这里只是摆列了一些对比有意思的部份. 检测器:找出 hash equals 不匹配 这个检测器探求与 equals() 和 hashCode() 的实现相关的几个问题.这两个办法非常重要,因为几近全部基于调集的类—— List、Map、Set 等都调用它们.普通来说,这个检测器探求两种差别范例的问题——当一个类: 重写对象的 equals() 办法,但是没有重写它的 hashCode 办法,大概相反的情形时. 定义一个 co-variant 版本的 equals() 或 compareTo() 办法.比方, Bob 类定义其 equals() 办法为布尔 equals(Bob) ,它覆盖了对象中定义的 equals() 办法.因为 Java 代码在编译时解析重载办法的方法,在运行时利用的几近老是在对象中定义的这个版本的办法,而不是在 Bob 中定义的那一个(除非显式将 equals() 办法的参数强迫转换为 Bob 范例).因此,当这个类的一个实例放入到类调集合的任何一此中时,利用的是 Object.equals() 版本的办法,而不是在 Bob 中定义的版本.在这种情形下, Bob 类该当定义一个承受范例为 Object 的参数的 equals() 办法. 检测器:忽视办法返回值 这个检测器查找代码中忽视了不该该忽视的办法返回值的地方.这种情形的一个常见例子是在调用 String 办法时,如在清单 1 中: 清单 1. 忽视返回值的例子 1 String aString = "bob"; 2 b.replace('b', 'p'); 3 if(b.equals("pop"))
这个错误很常见.在第 2 行,程序员认为他已经用 p 替换了字符串中的全部 b.确切是这样,但是他忘掉了字符串是不可变的.全部这类办法都返回一个新字符串,而历来不会改变消息的接纳者. 检测器:Null 指针对 null 的解引用(dereference)和冗余对比 这个检测器查找两类问题.它查找代码途径将会大概大概造成 null 指针非常的情形,它还查找对 null 的冗余对比的情形.比方,假如两个对比值都为 null,那么它们就是冗余的并大概表明代码错误.FindBugs 在可以肯定一个值为 null 而另一个值不为 null 时,检测近似的错误,如清单 2 所示: 清单 2. Null 指针示例 1 Person person = aMap.get("bob"); 2 if (person != null) { 3 person.updateAccessTime(); 4 } 5 String name = person.getName();
在这个例子中,假如第 1 行的 Map 不包含一个名为“bob”的人,那么在第 5 行询问 person 的名字时就会呈现 null 指针非常.因为 FindBugs 不知道 map 能否包含“bob”,所以它将第 5 行标志为大概 null 指针非常. 检测器:初始化之前读取字段 这个检测器探求在构造函数中初始化之前被读取的字段.这个错误普通是——固然不老是如此——由利用字段名而不是构造函数参数惹起的,如清单 3 所示: 清单 3. 在构造函数中读取未初始化的字段 1 public class Thing { 2 private List actions; 3 public Thing(String startingActions) { 4 StringTokenizer tokenizer = new StringTokenizer(startingActions); 5 while (tokenizer.hasMoreTokens()) { 6 actions.add(tokenizer.nextToken()); 7 } 8 } 9 }
在这个例子中,第 6 行将产生一个 null 指针非常,因为变量 actions 还没有初始化. 这些例子只是 FindBugs 所发现的问题种类的一小部份(更多信息请参阅 参考资料).在撰写本文时,FindBugs 供应总共 35 个检测器. 开始利用 FindBugs 要运行 FindBugs,需求一个版本 1.4 大概更高的 Java Development Kit (JDK),不过它可以解析由旧版本的 JDK 成立的类文件.要做的第一件事是下载并安装最新公布的 FindBugs——当前是 0.7.1 (请参阅 参考资料).幸运的是,下载和安装是相当简单的.在下载了 zip 大概 tar 文件后,将它解紧缩到所选的目录中.就是这样了——安装就完成了. 安装完后,通过一个示例类运行它.在此处我将针对 Windows 用户举行讲授.翻开号令行提醒标记并进入 FindBugs 的安装目录.比方: C:\apps\FindBugs-0.7.3. 在 FindBugs 主目录中,有几个值得注意的目录.文档在 doc 目录中,bin 目录包含了运行 FindBugs 的批处理文件,即运行FINDBUGS的关键. 运行 FindBugs 像目前的大大都数工具一样,可以以多种方法运行 FindBugs——从 GUI、从号令行、利用 Ant、作为 Eclipse 插件程序和利用 Maven.我将扼要说起从 GUI 运行 FindBugs,但是重点放在用 Ant 和号令行运行它.部份缘由是由于 GUI 没有供应号令行的全部选项.比方,当前不能指定要加入的过滤器大概在 UI 中解除特定的类.但是更重要的缘由是我认为 FindBugs 最好作为编译的集成部份利用,而 UI 不属于自动编译. 利用 FindBugs UI 利用 FindBugs UI 很直观,但是有几点值得阐明.如 图 1所示,利用 FindBugs UI 的一个好处是对每一个检测到的问题供应了阐明.图 1 显示了缺陷 Naked notify in method的阐明.对每一种缺陷情势供应了近似的阐明,在第一次熟习这种工具时这是很有效的.窗口下面的 Source code 选项卡也一样有效.假如奉告 FindBugs 在什么地方探求代码,它就会在转换到呼应的选项卡时突出显示有问题的那一行. 值得一提的还有在将 FinBugs 作为 Ant 任务大概在号令行中运行 FindBugs 时,挑选 xml 作为 ouput 选项,可以将上一次运行的后果装载到 UI 中.这样做是同时操纵基于号令行的工具和 UI 工具的长处的一个很好的办法. 将 FindBugs 作为 Ant 任务运行 让我们看一下如安在 Ant 编译脚本中利用 FindBugs.首先将 FindBugs Ant 任务拷贝到 Ant 的 lib 目录中,这样 Ant 就知道新的任务.将 FIND_BUGS_HOME\lib\FindBugs-ant.jar 拷贝到 ANT_HOME\lib. 目前看看在编译脚本中要加入什么才能利用 FindBugs 任务.因为 FindBugs 是一个自定义任务,将需求利用 taskdef 任务以使 Ant 知道装载哪一个类.通过在编译文件中加入以下一行做到这一点: <taskdef name="FindBugs" classname="edu.umd.cs.FindBugs.anttask.FindBugsTask"/>
在定义了 taskdef 后,可以用它的名字 FindBugs 引用它.下一步要在编译中加入利用新任务的目标,如清单 4 所示: 清单 4. 成立 FindBugs 目录 1 <target name="FindBugs" depends="compile"> 2 <FindBugs home="${FindBugs.home}" output="xml" outputFile="jedit-output.xml"> 3 <class location="c:\apps\JEdit4.1\jedit.jar" /> 4 <auxClasspath path="${basedir}/lib/Regex.jar" /> 5 <sourcePath path="c:\tempcbg\jedit" /> 6 </FindBugs> 7 </target>
让我们更具体地解析这段代码中所发生的历程. 第 1 行: 注意 target 取决于编译.一定要记着处理的是类文件而不是源文件,这样使 target 对应于编译目标保证了 FindBugs 可在最新的类文件运行.FindBugs 可以机动地承受多种输入,包含一组类文件、JAR 文件、大概一组目录. 第 2 行:必须指定包含 FindBugs 的目录,我是用 Ant 的一个属性完成的,以下所示: <property name="FindBugs.home" value="C:\apps\FindBugs-0.7.3" />
可选属性 output 指定 FindBugs 的后果利用的输分外式.大概的值有 xml 、 text 大概 emacs .假如没有指定 outputFile ,那么 FindBugs 会利用尺度输出.如前所述,XML 格局有可以在 UI 中傍观的额外好处. 第 3 行: class 元素用于指定要 FindBugs 解析哪些 JAR、类文件大概目录.解析多个 JAR 大概类文件时,要为每一个文件指定一个单独的 class 元素.除非加入了 projectFile 元素,不然需求 class 元素.更多细节请参阅 FindBugs 手册. 第 4 行: 用嵌套元素 auxClasspath 列出利用程序的依靠性.这些是利用程序需求但是不但愿 FindBugs 解析的类.假如没有列出利用程序的依靠关系,那么 FindBugs 仍旧会尽大概地解析类,但是在找不到一个贫乏的类时,它会抱怨.与 class 元素一样,可以在 FindBugs 元素中指定多个 auxClasspath 元素. auxClasspath 元素是可选的. 第 5 行: 假如指定了 sourcePath 元素,那么 path 属性该当表明一个包含利用程序源代码的目录.指定目录使 FindBugs 可以在 GUI 中查看 XML 后果时突出显示出错的源代码.这个元素是可选的. 上面就是基本内容了. 过滤器 您已经将 FindBugs 引入到了团队中,并运行它作为您的每小时/每晚编译历程的一部份.当团队越来越熟习这个工具时,出于某些缘由,您决意所检测到的一些缺陷关于团队来说不重要.大概您不关心一些类能否返回大概被恶意改正的对象——大概,像 JEdit,有一个真正需求的(honest-to-goodness)、合理的来由调用 System.gc() . 老是可以挑选“关闭”特定的检测器.在更细化的水平上,可以在指定的一组类乃至是办法中查找问题时,解除某些检测器.FindBugs 供应了这种细化的掌握,可以解除大概包含过滤器.当前只有效号令行大概 Ant 启动的 FindBugs 中支持解除和包含过滤器.正如其名字所表明的,利用解除过滤器来解除对某些缺陷的报告.较为少见但仍旧有效的是,包含过滤器只能用于报告指定的缺陷.过滤器是在一个 XML 文件中定义的.可以在号令行顶用一个解除大概包含开关、大概在 Ant 编译文件顶用 excludeFilter 和 includeFilter 指定它们.在下面的例子中,假定利用解除开关.还要注意在下面的谈论中,我对 “bugcode”、“bug” 和“detector”的利用具有某种程度的交换性. 可以有差别的方法定义过滤器: 匹配一个类的过滤器.可以用这些过滤器 忽视在特定类中发现的全部问题. 匹配一个类中特定缺陷代码(bugcode)的 过滤器.可以用这些过滤器忽视在特定类中发现的一些缺陷. 匹配一组缺陷的过滤器.可以用这些过滤器 忽视所解析的全部类中的一组缺陷. 匹配所解析的一个类中的某些办法的过滤器.可以用这些过滤器忽视在一个类中的一组办法中发现的全部缺陷. 匹配在所解析的一个类中的办法中发现的某些缺陷的过滤器.可以用这些过滤器忽视在一组办法中发现的特定缺陷. 知道了这些便可以开始利用了.有关其他定制 FindBugs 办法的更多信息,请参阅 FindBugs 文档.知道若何设置编译文件今后,就让我们更具体地解析若何将 FindBugs 集成到编译历程中吧!
以上是“解析代码漏洞:FindBugs[网络技术]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |