程式碼審計--19--FindBugs詳細
3.1 軟體介紹
Findbugs 是一個靜態分析工具,通過檢查類或者 JAR 檔案,將位元組碼與一組缺陷模式進行對比以發現可能的問題。Findbugs不注重style及format,注重檢測真正的bug及潛在的效能問題,尤其注意了儘可能抑制誤檢測(falsepositives)的發生。工具自帶了60餘種Bad practice,80餘種Correntness,1種Internationalization,12種Malicious code vulnerability,27種Multithreaded correntness,23種Performance,43種Dodgy。利用這個工具,就可以在不實際執行程式的情況對軟體進行分析。它可以幫助改進程式碼的質量。
Findbugs可以通過Ant工具,通過Ant提供的Swing操作介面和作為Eclipse的一個外掛來使用。
3.2 使用Findbugs
1、開始Findbugs Ant操作
Findbugs的Swing工具使用操作如下:
Findbugs 主介面:
在分析專案之前,通過新建一個專案來分析,選擇檔案->新建
然後新增要分析的類包和目錄(可以選擇編譯好的類所在的資料夾,也可以選擇生成的jar包),再新增輔助類所在的資料夾和原始檔所在的資料夾(java檔案所在的資料夾)。再點選完成就可以建立一個要分析的專案。
新建專案
建立專案後,會自動開始解析專案。解析後的結果介面如下所示:
其中左邊是缺陷的樹結構列表,點選其中一個Bug,可以在右邊的介面中,顯示Bugs的原始檔以及所在的位置。
2、開始Findbugs Eclipse外掛使用
Eclipse的Findbugs外掛,可以將Findbugs整合到Eclipse中使用。
安裝好Findbugs後啟動eclipse。在eclipse中選擇某個工程的屬性。如下圖所示:
點選“屬性”彈出屬性對話方塊,選擇對話方塊左邊的樹上的“Findbugs”節點:
下面對Findbugs各項屬性的配置進行一下說明:
1、Run Findbugs automnaticaly:編譯工程和檔案的時候自動執行 2、Minimum priority to report:根據bug的優先權級別報告bug。 3、Enable bug categories: bug種類。 ----Correctness:正確性。 ----Performance:效能。 ----Internationalization:國際化。 ----Mutithreaded correctness:多執行緒的正確性。 ----Style:樣式。 ----Malicious code vulnerability:惡意程式碼。 4、Select bug patterns to check for: bug的校驗模式 ----Bug的校驗模式的設定是確定哪一類問題應該作為bug報告給使用者。
當根據部門規範選擇要校驗的模式後。點選”ok” 按鈕就可以對工程進行校驗。 如下圖:在工程的選單中選擇findbugs的選單項“Find bugs”。
執行後可以在problems檢視中看到工程的所有可能的“偽問題”
Findbugs的問題描述一般都是:問題型別+‘:’+問題描述構成的。如果想看到詳細的問題描述,可以選擇問題然後點選右鍵選單,在“bug Details”檢視中看到相應的說明。如下圖所示:
Bug選擇的其他方式:
另外,如果想看到僅僅是Findbugs檢查出來的問題的話可以對問題列表進行過濾。如下圖所示的方法可以實現問題過濾:
如果想要檢視某個Bug詳細的資訊,則可以選擇Windows選單->Open Perspective,然後選擇FindBugs就可以開啟FindBugs的Properties面板,在這個面板裡面可以看到最詳盡的Bugs資訊。
3.3 Bug分類表
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屬性。