代码审计--18--PMD详细

版权声明:本文为博主原创文章,转载本站文章请注明作者和出处,请勿用于任何商业用途。 https://blog.csdn.net/wutianxu123/article/details/82950084

2.1 PMD概述

1、工具说明

PMD是一个代码检查工具,它用于分析Java源代码,找出潜在的问题。

PMD的核心是JavaCC解析器生成器。PMD附带了16个可以直接使用的规则信,利用这些规则可以找出Java源程序的许多问题;此外,PMD规则是可以定制的,可以添加新规则:通过编写Java代码并重新编译PDM,或者更简单些,编写XPath表达式,它会针对每个Java类的抽象语法树进行处理,检查Java代码是否符合某些特定的编码规范。

PMD已经与JDeveloper、Eclipse、jEdit、JBuilder、BlueJ、CodeGuide、NetBeans、Sun Java Studio Enterprise/Creator、IntelliJIDEA、TextPad、Maven、Ant、Gel、JCreator以及Emacs集成在一起。

2、PMD基本功能

利用PMD进行静态代码检测可以找出Java源程序的以下问题:

潜在的bug:空的try/catch/finally/switch语句。
未使用的代码:未使用的局部变量、参数、私有方法等。
可选的代码:String/StringBuffer的滥用。
复杂的表达式:不必要的if语句、可以使用while循环完成的for循环。
重复的代码:拷贝/粘贴代码意味着拷贝/粘贴bugs。
循环体创建新对象:尽量不要在for或while循环体内实例化一个新对象。
资源关闭:Connect,Result,Statement等使用之后确保关闭掉。

2.2 使用PMD

1、开始运行

PMD 是用 Java 编程语言编写的,并且要求使用 JDK 1.3 或更高的版本。如果使用命令行,那么 PMD 的安装和运行会非常简单。

运行 PMD 最简单的方法是调用脚本 pmd.sh(在 Unix/Linux 上)或脚本 pmd.bat(在 Windows 上)。不太合常规的是,这些脚本在 pmd-2.1/etc 目录中,而不是在 bin 目录中。这个脚本采用了三个命令行参数:

要检查的 .java 文件的路径。
指定输出格式的关键字 html 或 xml。
要运行的规则集的名称。

以下命令使用命名规则集检查 ImageGrabber.java 文件并生成 XML 输出

$ /usr/pmd-2.1/etc/pmd.sh ImageGrabber.java xml rulesets/naming.xml

2、审计结果查看分析

默认报告
默认情况下,结果输出类似于以下报告,这些输出被发送到 System.out:

PMD 的 XML 报告

<?xml version="1.0"?>
<pmd>
	<file name="/Users/elharo/src/ImageGrabber.java">
		<violation line="32" rule="ShortVariable"  ruleset="Naming Rules" priority="3">
			Avoid variables with short names like j
		</violation>

		<violation line="105" rule="VariableNamingConventionsRule"  ruleset="Naming Rules" priority="1">
			Variables that are not final should not contain underscores 
		</violation>
	</file>
	<error filename="/Users/elharo/src/ImageGrabber.java"  msg="Error while processing /Users/elharo/ImageGrabber.java"/>
</pmd>

在上面的例子中可以看到,PMD 发现了两个问题:在 ImageGrabber.java 有一个短变量名称,名称中有一个下划线。这些看起来可能是小问题,但是经过仔细考察,可以完全排除 j 变量,因为它与另外一个单独递增变量的功能相同。

HTML报告

可以把 PMD 的输出重定向到文件中、或者通过管道,以常见的方式将它传递到编辑器中。通常HTML 格式的报告更为直观的展示了审计结果

在这里插入图片描述

在检查源代码树时,把结果输出到文件中会非常有帮助。当结果中生成误报(false positive)的时候,可以很容易地从文件中认出并删除最常见的误报,因为它们通常非常相似;然后您就可以解决其余的问题。

PMD 中惟一缺乏的特性就是不能向源代码中添加 “lint 注释”,以便对要执行的一些明显有危险的操作进行提醒。

3、PMD内置规则集

基本(rulesets/basic.xml)—— 规则的一个基本合集,可能大多数开发人员都不认同它: catch 块不该为空,无论何时重写 equals(),都要重写 hashCode(),等等。

命名(rulesets/naming.xml)—— 对标准 Java 命令规范的测试:变量名称不应太短;方法名称不应过长;类名称应当以小写字母开头;方法和字段名应当以小写字母开头,等等。

未使用的代码(rulesets/unusedcode.xml)—— 查找从未使用的私有字段和本地变量、执行不到的语句、从未调用的私有方法,等等。

设计(rulesets/design.xml)—— 检查各种设计良好的原则,例如: switch 语句应当有 default 块,应当避免深度嵌套的 if 块,不应当给参数重新赋值,不应该对 double 值进行相等比较。

导入语句(rulesets/imports.xml)—— 检查 import 语句的问题,比如同一个类被导入两次或者被导入 java.lang 的类中。

JUnit 测试(rulesets/junit.xml)—— 查找测试用例和测试方法的特定问题,例如方法名称的正确拼写,以及 suite() 方法是不是 static 和 public。

字符串(rulesets/string.xml)—— 找出处理字符串时遇到的常见问题,例如重复的字符串标量,调用 String 构造函数,对 String 变量调用 toString() 方法。

括号(rulesets/braces.xml)—— 检查 for、 if、 while 和 else 语句是否使用了括号。

代码尺寸(rulesets/codesize.xml)—— 测试过长的方法、有太多方法的类以及重构方面的类似问题。

Javabean(rulesets/javabeans.xml)—— 查看 JavaBean 组件是否违反 JavaBean 编码规范,比如没有序列化的 bean 类。

终结函数(finalizer)—— 因为在 Java 语言中, finalize() 方法不是那么普遍,所以它们的使用规则虽然很详细,但是人们对它们相对不是很熟悉。这类检查查找 finalize() 方法的各种问题,例如空的终结函数,调用其他方法的 finalize() 方法,对 finalize() 的显式调用,等等。

克隆(rulesets/clone.xml)—— 用于 clone() 方法的新规则。凡是重写 clone() 方法的类都必须实现 Cloneable, clone() 方法应该调用 super.clone(),而 clone() 方法应该声明抛出 CloneNotSupportedException 异常,即使实际上没有抛出异常,也要如此。

耦合(rulesets/coupling.xml)—— 查找类之间过度耦合的迹象,比如导入内容太多;在超类型或接口就已经够用的时候使用子类的类型;类中的字段、变量和返回类型过多等。

严格的异常(rulesets/strictexception.xml)—— 针对异常的测试:不应该声明该方法而抛出 java.lang.Exception 异常,不应当将异常用于流控制,不应该捕获 Throwable,等等。

有争议的(rulesets/controversial.xml)—— PMD 的有些规则是有能力的 Java 程序员可以接受的。但还是有一些争议。这个规则集包含一些更有问题的检验,其中包括把 null 赋值给变量、方法中有多个返回点,以及从 sun 包导入等。

日志(rulesets/logging-java.xml)—— 查找 java.util.logging.Logger 的不当使用,包括非终状态(nonfinal)、非静态的记录器,以及在一个类中有多个记录器。

4、构建规则集

当需要频繁地用某个规则集合进行检查,可以把这些规则组合在规则集文件中,如下例子所示,这个规则集导入了一些基本规则、命名规则和设计规则:

导入基本规则、命名规则和设计规则的规则集

<?xml version="1.0"?>
<ruleset name="customruleset">
	<description>
		Sample ruleset for developerWorks article
	</description>
<rule ref="rulesets/design.xml"/>

<ruleref="rulesets/naming.xml"/>
	<rule ref="rulesets/basic.xml"/>
</ruleset>

可以从每个规则集中选取每个想要包含的规则。下面的例子显示了一个定制规则集,它从三个内置规则集中选取了 11 个特定的规则。因为检查大型的代码基址需要的时间相当长,即使是在快速硬件上也是如此,所以这种方法可以更快地发现要查找的特定问题。

导入 11 个特定规则的规则集

<?xml version="1.0"?>
<ruleset name="specific rules">
	<description>
		Sample ruleset for developerWorks article
	</description>

	<rule ref="rulesets/design.xml/AvoidReassigningParametersRule"/>
	<rule ref= "rulesets/design.xml/ConstructorCallsOverridableMethod"/>
	<rule ref="rulesets/design.xml/FinalFieldCouldBeStatic"/>
	<rule ref="rulesets/design.xml/DefaultLabelNotLastInSwitchStmt"/>
	<rule ref="rulesets/naming.xml/LongVariable"/>
	<rule ref="rulesets/naming.xml/ShortMethodName"/>
	<rule ref="rulesets/naming.xml/VariableNamingConventions"/>
	<rule ref="rulesets/naming.xml/MethodNamingConventions"/>
	<rule ref="rulesets/naming.xml/ClassNamingConventions"/>
	<rule ref="rulesets/basic.xml/EmptyCatchBlock"/>
	<rule ref="rulesets/basic.xml/EmptyFinallyBlock"/>
</ruleset>

可以把大多数规则包含在一个集合,但是排除不需要的和会造成大量误报的特定规则。例如,XOM 在进行表查找的时候经常使用没有 default 块的switch 语句。可以保留大多数设计规则,但是可以在导入设计规则的规则元素中添加<exclude name="SwitchStmtsShouldHaveDefault"/>子元素,避开对遗漏default 块的检查,如下例子 所示:

排除了设计规则的规则集

<?xml version="1.0"?>
<ruleset name="dW rules">
	<description>
		Sample ruleset for developerWorks article
	</description>

	<rule ref="rulesets/design.xml">
		<exclude name="SwitchStmtsShouldHaveDefault"/>
	</rule>
</ruleset>

可用的规则并不仅限于内置规则,可以添加新规则:可以通过编写 Java 代码并重新编译 PDM,或者更简单些,编写 XPath 表达式,它会针对每个 Java 类的抽象语法树进行处理。

猜你喜欢

转载自blog.csdn.net/wutianxu123/article/details/82950084
PMD