目前已轉(zhuǎn)至個(gè)人博客凭舶,本系列地址:Lam's Blog - Knowledge as Action
前言
FindBugs是一個(gè)幫助項(xiàng)目發(fā)現(xiàn)Bug的靜態(tài)分析工具又沾,因?yàn)镕indBugs分析報(bào)告都為英文罐盔,而且只有這個(gè)問(wèn)題的描述篮赢,所以接下來(lái)將會(huì)通過(guò)多篇文章以Bad Practice奏甫、Correctness尖飞、Style等FindBugs錯(cuò)誤類(lèi)型為分類(lèi)進(jìn)行整理症副,每篇文章會(huì)對(duì)每個(gè)出現(xiàn)的問(wèn)題盡量按照以下的方式給出詳細(xì)的說(shuō)明
- 問(wèn)題描述的翻譯
- 為什么會(huì)產(chǎn)生這個(gè)問(wèn)題
- 怎么解決這個(gè)問(wèn)題
由于個(gè)人遇到的錯(cuò)誤類(lèi)型有限,所以該系列文章會(huì)整合項(xiàng)目中遇到的和網(wǎng)上找到的問(wèn)題政基,有遺漏的或者錯(cuò)誤的地方也會(huì)持續(xù)補(bǔ)充和修改贞铣,想要查找具體問(wèn)題的同學(xué)可以到相對(duì)應(yīng)的文章里面按照Bug名稱(chēng)進(jìn)行搜索。
簡(jiǎn)介
Findbugs是一個(gè)靜態(tài)分析工具沮明,它檢查類(lèi)或者JAR 文件辕坝,將字節(jié)碼與一組缺陷模式進(jìn)行對(duì)比以發(fā)現(xiàn)可能的問(wèn)題。Findbugs自帶檢測(cè)器珊擂,其中有60余種Bad practice圣勒,80余種Correctness,1種 Internationalization摧扇,12種Malicious code vulnerability圣贸,27種Multithreaded correctness,23種Performance扛稽,43種Dodgy吁峻。我們還可以自己配置檢查規(guī)則(做哪些檢查,不做哪些檢查),也可以自己來(lái)實(shí)現(xiàn)獨(dú)有的校驗(yàn)規(guī)則(用戶(hù)自定義特定的bug模式需要繼承它的接口,編寫(xiě)自己的校驗(yàn)類(lèi),屬于高級(jí)技巧)在张。
白盒測(cè)試中的靜態(tài)檢查一般是檢查編碼標(biāo)準(zhǔn)規(guī)范用含,錯(cuò)誤列表。編碼規(guī)范往往團(tuán)隊(duì)會(huì)根據(jù)自己的經(jīng)驗(yàn)和風(fēng)格進(jìn)行設(shè)置一些規(guī)范“镓遥現(xiàn)在很多IDE工具都會(huì)在編輯代碼的時(shí)候?qū)崟r(shí)的提醒是否符合代碼風(fēng)格啄骇。錯(cuò)誤列表,一般是代碼潛在的bug瘟斜,由于某種代碼寫(xiě)法雖然沒(méi)有語(yǔ)法錯(cuò)誤缸夹,但是可能存在錯(cuò)誤,比如會(huì)導(dǎo)致線(xiàn)程死鎖螺句。這些都是錯(cuò)誤列表應(yīng)該檢查的虽惭。靜態(tài)檢查的可操作方式:
- 代碼走查
程序員之間可以隔一定的時(shí)間抽取代碼進(jìn)行走查。
走查的時(shí)候根據(jù)匯總報(bào)告蛇尚,把這些經(jīng)驗(yàn)匯成列表芽唇,作為下次代碼走查的依據(jù)。
該方式的特點(diǎn)是取劫,手工匆笤、多人討論研侣、操作簡(jiǎn)單,但是效率會(huì)比較低疚膊。 - 代碼掃描
使用軟件對(duì)我們的代碼進(jìn)行掃描义辕,查找出潛在的問(wèn)題。現(xiàn)在有許多商業(yè)的工具能夠進(jìn)行掃描寓盗,比如Parasoft JTest灌砖、Software Analyzer、pclint等工具傀蚌,往往不同的工具會(huì)針對(duì)不同的語(yǔ)言基显。當(dāng)然也有很多開(kāi)源的工具。在這里java方面主要推薦Findbugs善炫。Findbugs可以在多個(gè)環(huán)境中運(yùn)行撩幽,同時(shí)也可以編寫(xiě)自己的檢測(cè)器,功能比較完善箩艺。我們平時(shí)可以收集自己的或者是別人的開(kāi)發(fā)經(jīng)驗(yàn)窜醉,把它做成檢測(cè)器來(lái)完善Findbugs的檢測(cè)體系。軟件掃描的特點(diǎn)是艺谆,機(jī)器掃描榨惰、效率高,但是不夠靈活静汤。
FindBugs在Android Studio上應(yīng)用
- 插件
首先打開(kāi)Android Studio的的插件界面琅催,輸入FindBugs,點(diǎn)擊Browse查找,選擇FindBugs-IDEA然后單擊右側(cè)的Install plugin按鈕進(jìn)行安裝虫给,重啟IDE即可在下方看到FindBugs選項(xiàng)藤抡。 - Gradle
apply plugin: "findbugs"
task findbugs(type: FindBugs) {
//toolVersion = "3.0.1"
gnoreFailures= true
effort= "max"
reportLevel= "low"
classes = files("$project.buildDir/intermediates/classes")
source= fileTree('build/intermediates/classes/debug/com/sn/')
classpath= files()
reports{
xml {
destination "build/findbugs.xml"
}
}
- Jenkins
在Gradle中添加FindBugs相關(guān)的task后可以在Jenkins中配置該task到構(gòu)建模塊中實(shí)現(xiàn)自動(dòng)集成
FindBugs錯(cuò)誤類(lèi)型說(shuō)明
Bad practice 壞的實(shí)踐,下面列舉幾個(gè):
HE:類(lèi)中equals()與hashCode()沒(méi)有同時(shí)定義抹估,或者使用了錯(cuò)誤的對(duì)象的hashCode()或equals()缠黍。
SQL:Statement 的execute方法調(diào)用了非常量的字符串;或Prepared Statement是由一個(gè)非常量的字符串產(chǎn)生药蜻。
DE: 方法終止或不處理異常瓷式,一般情況下,異常應(yīng)該被處理或報(bào)告谷暮,或被方法拋出蒿往。Correctness 一般的正確性問(wèn)題盛垦,可能導(dǎo)致錯(cuò)誤的代碼湿弦,下面列舉幾個(gè):
NP: 空指針被引用;在方法的異常路徑里腾夯,空指針被引用颊埃;方法沒(méi)有檢查參數(shù)是否null蔬充;null值產(chǎn)生并被引用;null值產(chǎn)生并在方法的異常路徑被引用班利;傳給方法一個(gè)聲明為@NonNull的null參數(shù)饥漫;方法的返回值聲明為@NonNull實(shí)際是null。
Nm: 類(lèi)定義了hashcode()方法罗标,但實(shí)際上并未覆蓋父類(lèi)Object的hashCode()庸队;類(lèi)定義了tostring()方法,但實(shí)際上并未覆蓋父類(lèi)Object的toString()闯割;很明顯的方法和構(gòu)造器混淆彻消;方法名容易混淆。
SQL:方法嘗試訪問(wèn)一個(gè)Prepared Statement的0索引宙拉;方法嘗試訪問(wèn)一個(gè)ResultSet的0索引宾尚。
UwF:所有的write都把屬性置成null,這樣所有的讀取都是null谢澈,這樣這個(gè)屬性是否有必要存在煌贴;或?qū)傩詮臎](méi)有被write。Internationalization 國(guó)際化锥忿,當(dāng)對(duì)字符串使用upper或lowercase方法牛郑,如果是國(guó)際的字符串,可能會(huì)不恰當(dāng)?shù)霓D(zhuǎn)換缎谷。
Malicious code vulnerability 可能受到的惡意攻擊井濒,如果代碼公開(kāi),可能受到惡意攻擊的代碼列林,下面列舉幾個(gè):
FI: 一個(gè)類(lèi)的finalize()應(yīng)該是protected瑞你,而不是public的。
MS:屬性是可變的數(shù)組希痴;屬性是可變的Hashtable者甲;屬性應(yīng)該是package protected的。Multithreaded correctness 多線(xiàn)程的正確性砌创,多線(xiàn)程編程時(shí)虏缸,可能導(dǎo)致錯(cuò)誤的代碼,下面列舉幾個(gè):
ESync:空的同步塊嫩实,很難被正確使用刽辙。
MWN:錯(cuò)誤使用notify(),可能導(dǎo)致IllegalMonitorStateException異常甲献;或錯(cuò)誤的使用wait()宰缤。
No: 使用notify()而不是notifyAll(),只是喚醒一個(gè)線(xiàn)程而不是所有等待的線(xiàn)程。
SC: 構(gòu)造器調(diào)用了Thread.start()慨灭,當(dāng)該類(lèi)被繼承可能會(huì)導(dǎo)致錯(cuò)誤朦乏。Performance 性能問(wèn)題,可能導(dǎo)致性能不佳的代碼氧骤,下面列舉幾個(gè):
DM:方法調(diào)用了低效的Boolean的構(gòu)造器呻疹,而應(yīng)該用Boolean.valueOf(…);用類(lèi)似Integer.toString(1) 代替new Integer(1).toString()筹陵;方法調(diào)用了低效的float的構(gòu)造器刽锤,應(yīng)該用靜態(tài)的valueOf方法。
SIC:如果一個(gè)內(nèi)部類(lèi)想在更廣泛的地方被引用朦佩,它應(yīng)該聲明為static姑蓝。
SS: 如果一個(gè)實(shí)例屬性不被讀取,考慮聲明為static吕粗。
UrF:如果一個(gè)屬性從沒(méi)有被read纺荧,考慮從類(lèi)中去掉。
UuF:如果一個(gè)屬性從沒(méi)有被使用颅筋,考慮從類(lèi)中去掉宙暇。Dodgy 危險(xiǎn)的,具有潛在危險(xiǎn)的代碼议泵,可能運(yùn)行期產(chǎn)生錯(cuò)誤占贫,下面列舉幾個(gè):
CI: 類(lèi)聲明為final但聲明了protected的屬性。
DLS:對(duì)一個(gè)本地變量賦值先口,但卻沒(méi)有讀取該本地變量型奥;本地變量賦值成null,卻沒(méi)有讀取該本地變量碉京。
ICAST: 整型數(shù)字相乘結(jié)果轉(zhuǎn)化為長(zhǎng)整型數(shù)字厢汹,應(yīng)該將整型先轉(zhuǎn)化為長(zhǎng)整型數(shù)字再相乘。
INT:沒(méi)必要的整型數(shù)字比較谐宙,如X <= Integer.MAX_VALUE烫葬。
NP: 對(duì)readline()的直接引用,而沒(méi)有判斷是否null凡蜻;對(duì)方法調(diào)用的直接引用搭综,而方法可能返回null。
REC:直接捕獲Exception划栓,而實(shí)際上可能是RuntimeException兑巾。
ST: 從實(shí)例方法里直接修改類(lèi)變量,即static屬性忠荞。
其他文章(持續(xù)更新)
FindBugs 規(guī)則整理:CORRECTNESS
FindBugs 規(guī)則整理:Bad Practice
FindBugs 規(guī)則整理:Style & Dodgy
FindBugs 規(guī)則整理:Malicious Code Vulnerability
FindBugs 規(guī)則整理:Multithreaded Correctness
FindBugs 規(guī)則整理:Security & Experimental
FindBugs 規(guī)則整理:Performance
FindBugs 規(guī)則整理:Internationalization