靜態分析工具及使用總結(三)
?
這里主要介紹三種開源的工具,PMD、CheckStyle和FindBugs,著重是在Ant里的調用,據說商業軟件JTest也是著名的代碼分析工具,哈哈,要花錢的沒有用過。
?
FindBugs(http://findbugs.sourceforge.net/)版本1.1.1
簡介:findbugs
是一個在java程序中查找bug的程序,它查找bug模式的實例,也就是
可能出錯的代碼實例,
?????? 注意findbugs是檢查java字節碼,也就是*.class文件。
用法:在圖形界面下使用findbugs,可以新建一個工程,設置類的路徑和源代碼的路徑,
詳細的文檔請參考官方文檔。
?????? 下面主要介紹在Ant里的調用。
? 下面是build.xml的相關配置:
<
path?
id
="findbugs.path"
>
???<
fileset?
dir
="${lib.dir}/findbugs-1.1.1"
>
???????<
include?
name
="**/*.jar"
?
/>
???</
fileset
>
</
path
>
<
taskdef?
name
="findbugs"
?classname
="edu.umd.cs.findbugs.anttask.FindBugsTask"
?classpathref
="findbugs.path"
/>
<!--
?以上定義findbugs的task?
-->

<
property?
name
="findbugs.home"
?value
="${lib.dir}/findbugs-1.1.1"
?
/>
<!--
?定義findbugs的home,findbugs的task要使用?
-->

?<
target?
name
="findbugs"
>
????<
findbugs?
home
="${findbugs.home}"
?includeFilter?
=?"${lib.dir}\findbugs-1.1.1\?plugin\filter.xml"
?output
="html"
?outputFile
="d:\test.html"
?
>
????????<
class?
location
="${class.dir}/classes/?"
?
/>
????????<!--
?以上定義findbugs查找的類路徑?
-->
????????<
auxClasspath?
refid
="classpath"
/>
????????<!--
?以上定義上述類所依賴的類路徑?
-->
????????<
sourcePath?
path
="${src.dir}"
?
/>
????????<!--
?以上定義源代碼的路徑?
-->
????</
findbugs
>
</
target
>
????? 其中的${lib.dir}\findbugs-1.1.1\ plugin\filter.xml配置文件的內容如下:
使用過濾器我們就可以定義使用哪些bug檢測器和針對哪些類進行檢查,因為一旦
項目比較龐大,
????? 那查看冗長的bug報告也是十分痛苦的事情。
<
FindBugsFilter
>
????
<!--
?該類使用所有的bug檢測器?
-->
????
<
Match?
class
="com.foobar.AClass"
>
????
????
<!--
?該類使用bugcode為HE的檢測器?
-->
????
<
Match?
class
="com.foobar.BClass"
>
????????
<
BugCode?
name
="HE"
?
/>
????
</
Match
>
????
<!--
?該類的AMethod和BMethod方法使用bugcode為HE的檢測器?
-->
????
<
Match?
class
="com.foobar.CClass"
>
????????
<
Or
>
????????????
<
Method?
name
="AMethod"
/>
????????????
<
Method?
name
="BMethod"
/>
????????
</
Or
>
????????
<
BugCode?
name
="HE"
/>
????
</
Match
>
?
</
FindBugsFilter
>
自帶檢測器的介紹:
findbugs
自帶60余種Bad practice,80余種Correntness,1種
Internationalization
,
??? 12種Malicious code vulnerability,27種Multithreaded correntness,23種Performance,43種Dodgy。
Bad practice
壞的實踐
一些不好的實踐,下面列舉幾個:
HE
:
類定義了equals(),卻沒有hashCode();或類定義了equals(),卻使用Object. hashCode();或類定義了hashCode(),卻沒有equals();或類定義了hashCode(),卻使用Object.equals();類繼承了equals(),卻使用Object.hashCode()。
SQL
:
Statement
的execute方法調用了非常量的字符串;或Prepared Statement是由一個非常量的字符串產生。
DE
:
方法終止或不處理異常,一般情況下,異常應該被處理或報告,或被方法拋出。
Correctness
一般的正確性問題
可能導致錯誤的代碼,下面列舉幾個:
NP
:
空指針被引用;在方法的異常路徑里,空指針被引用;方法沒有檢查參數是否null;null值產生并被引用;null值產生并在方法的異常路徑被引用;傳給方法一個聲明為@NonNull的null參數;方法的返回值聲明為@NonNull實際是null。
Nm
:
類定義了hashcode()方法,但實際上并未覆蓋父類Object的hashCode();類定義了tostring()方法,但實際上并未覆蓋父類Object的toString();很明顯的方法和構造器混淆;方法名容易混淆。
SQL
:
方法嘗試訪問一個Prepared Statement的0索引;方法嘗試訪問一個ResultSet的0索引。
UwF
:
所有的write都把屬性置成null,這樣所有的讀取都是null,這樣這個屬性是否有必要存在;或屬性從沒有被write。
Internationalization
國際化
當對字符串使用upper或lowercase方法,如果是國際的字符串,可能會不恰當的轉換。
????
???Malicious code vulnerability
可能受到的惡意攻擊
???
如果代碼公開,可能受到惡意攻擊的代碼,下面列舉幾個:
??? FI
:
一個類的finalize()應該是protected,而不是public的。
???
MS
:
屬性是可變的數組;屬性是可變的Hashtable;屬性應該是package protected的。
???
???Multithreaded correctness
多線程的正確性
???
多線程編程時,可能導致錯誤的代碼,下面列舉幾個:
???
ESync
:
空的同步塊,很難被正確使用。
???
MWN
:
錯誤使用notify(),可能導致IllegalMonitorStateException異常;或錯誤的
使用wait()。
No
:
使用notify()而不是notifyAll(),只是喚醒一個線程而不是所有等待的線程。
SC
:
構造器調用了Thread.start(),當該類被繼承可能會導致錯誤。
???
???
Performance
性能問題
???
可能性能不佳的代碼,下面列舉幾個:
???
DM
:
方法調用了低效的Boolean的構造器,而應該用Boolean.valueOf(…);用類似
Integer.toString(1)
代替new Integer(1).toString();方法調用了低效的float的構造器,應該用靜態的valueOf方法。
SIC
:
如果一個內部類想在更廣泛的地方被引用,它應該聲明為static。
SS
:
如果一個實例屬性不被讀取,考慮聲明為static。
UrF
:
如果一個屬性從沒有被read,考慮從類中去掉。
UuF
:
如果一個屬性從沒有被使用,考慮從類中去掉。
???
??? Dodgy
危險的
???
具有潛在危險的代碼,可能運行期產生錯誤,下面列舉幾個:
???
BC
:
對抽象集合如List、Set的造型;對具體集合如ArrayList、HashSet的造型;
未檢查或無法保證的造型;
CI
:
類聲明為final但聲明了protected的屬性。
DLS
:
對一個本地變量賦值,但卻沒有讀取該本地變量;本地變量賦值成null,卻沒有讀取該本地變量。
ICAST
:
整型數字相乘結果轉化為長整型數字,應該將整型先轉化為長整型數字再相乘。
INT
:
沒必要的整型數字比較,如X <= Integer.MAX_VALUE。
NP
:
對readline()的直接引用,而沒有判斷是否null;對方法調用的直接引用,而方法可能返回null。
REC
:
直接捕獲Exception,而實際上可能時RuntimeException。
ST
:
從實例方法里直接修改類變量,即static屬性。
?
自定義檢測器:
findbugs
提供了強大的自定義檢測器的功能,首先我們應該清楚需要
檢查的案例,findbugs的官方文檔里并沒有詳細的介紹如何自定義,那我們只能直接閱讀它的源碼了,著重閱讀BytecodeScanningDetector和ByteCodePatternDetector的子類型,它們可以檢測一般類型的問題。Findbugs利用了Byte Code Engineering Library(即BCEL,Apache上的一個開源項目),以實現其檢測器,所有的字節碼掃描都是基于visitor模式。我們可以參照findbugs自帶的檢測器的類的源碼,去編寫一個自定義的檢測器代碼,編寫完后編譯成類文件,同時我們還需要提供兩個XML文件,Findbugs.xml和message.xml,在Findbugs.xml里指定檢測器和實現類,檢測器的縮寫、類型如快速或慢速,而message文件里則包括了該檢測器的描述信息,可能是html的,然后將源文件、類文件和上面兩個XML文件打包成jar文件,放在findbugs home的plugin文件夾下,這樣我們就可以使用自定義檢查器了。
?
參考文檔:
FindBugs
官方文檔(http://findbugs.sourceforge.net/)
FindBugs
,第 1 部分: 提高代碼質量
http://www-128.ibm.com/developerworks/cn/java/j-findbug1/
FindBugs
,第 2 部分: 編寫自定義檢測器
http://www-128.ibm.com/developerworks/cn/java/j-findbug2/
代碼靜態分析(http://blog.donews.com/foxgem/archive/2005/04/23/347444.aspx)