趙彥紅
通號(hào)工程局集團(tuán)北京研究設(shè)計(jì)實(shí)驗(yàn)中心有限公司 北京 100070
隨著近來(lái)軟件行業(yè)的迅猛發(fā)展,以及人們對(duì)軟件需求的日益增長(zhǎng),軟件的質(zhì)量越來(lái)越成為人們關(guān)注的對(duì)象,保證軟件質(zhì)量的途徑有兩種:一種是設(shè)計(jì)階段盡量避免缺陷,另一種就是軟件開(kāi)發(fā)完成后的測(cè)試。軟件的測(cè)試按功能性可分為白盒測(cè)試、黑盒測(cè)試和灰盒測(cè)試;從是否執(zhí)行程序角度可分為動(dòng)態(tài)測(cè)試和靜態(tài)測(cè)試。本文主要研究的是靜態(tài)測(cè)試,靜態(tài)測(cè)試不實(shí)際運(yùn)行軟件,主要對(duì)軟件的編程格式、結(jié)構(gòu)等方面進(jìn)行評(píng)估。靜態(tài)測(cè)試包括代碼規(guī)范性檢查、靜態(tài)結(jié)構(gòu)分析和代碼質(zhì)量檢查等,可人工完成,也可借助軟件工具進(jìn)行。靜態(tài)分析工具能自動(dòng)找出代碼中已有的缺陷[1]。好的靜態(tài)分析工具是測(cè)試過(guò)程中不可或缺的利器,可在短時(shí)間內(nèi)通過(guò)分析或檢查源程序的語(yǔ)法、結(jié)構(gòu)、過(guò)程、接口等來(lái)檢查程序的正確性,找出代碼隱藏的錯(cuò)誤和缺陷,如參數(shù)不匹配,有歧義的嵌套語(yǔ)句,錯(cuò)誤的遞歸,可能出現(xiàn)的空指針引用等[2]。
Eclipse是一款開(kāi)源的基于java的可擴(kuò)展開(kāi)發(fā)平臺(tái)。開(kāi)源性決定了任何人都可以對(duì)Eclipse實(shí)施開(kāi)發(fā)插件的過(guò)程,可擴(kuò)展決定了java功能的可完善性和易維護(hù)性。所以,Eclipse插件就是集成在Eclipse平臺(tái)中的實(shí)現(xiàn)不同功能的工具。
Find Bugs是一個(gè)能靜態(tài)分析源代碼中可能會(huì)出現(xiàn)bug的Eclipse插件工具。它檢查類(lèi)文件,將字節(jié)碼(bytecode存在于編譯后的.class文件中)與一組缺陷模式和集成的規(guī)范進(jìn)行對(duì)比以發(fā)現(xiàn)可能的問(wèn)題。有了靜態(tài)分析工具,就可以在不實(shí)際運(yùn)行程序中對(duì)源代碼進(jìn)行分析。不是通過(guò)分析類(lèi)文件(.class的文件) 的形式或結(jié)構(gòu)來(lái)確定程序的意圖,而是使用Visitor模式[3]對(duì)文件進(jìn)行掃描和分析,在不改變?cè)创a的情況下,檢測(cè)出源代碼中的存在的潛在性問(wèn)題。
Find Bugs是由許多不同特性的JAR文件組成,這些JAR文件可以通過(guò)Eclipse運(yùn)行實(shí)現(xiàn)自己的功能。而這些功能是可選的,所以在進(jìn)行測(cè)試時(shí),可以根據(jù)需要來(lái)選擇功能。這正是Find Bugs的方便之處,也是插件開(kāi)發(fā)者能夠進(jìn)行方便開(kāi)發(fā)的前提。
開(kāi)發(fā)流程圖如下:
圖1 開(kāi)發(fā)流程圖
進(jìn)行Java開(kāi)發(fā)過(guò)程中,Eclipse的使用是不可避免的,而基于Eclipse的Find Bugs插件在前期能夠減少代碼出現(xiàn)錯(cuò)誤和避免不好的編碼習(xí)慣。
Find Bugs將檢測(cè)到的錯(cuò)誤分為以下幾類(lèi):Bad practice,Correctness,Internationalization,Malicious code vulnerability,Multithreaded correctness,Performance,Dodgy code,Security,Experimental??梢?jiàn)Find Bugs插件不僅是檢查代碼的漏洞和錯(cuò)誤,還會(huì)檢查代碼的書(shū)寫(xiě)習(xí)慣、安全性能、多線程以及國(guó)際通用性等問(wèn)題。
本文設(shè)計(jì)的插件就是屬于Find Bugs中的Bad practice,本文所開(kāi)發(fā)的插件主要檢查Java代碼中空的try/catch塊。眾所周知,異常檢測(cè)在Java開(kāi)發(fā)中是一個(gè)重要的環(huán)節(jié),其語(yǔ)句如下:
其中try語(yǔ)句用來(lái)捕獲異常,而catch語(yǔ)句用來(lái)打印異常信息。異常信息對(duì)于Java代碼的調(diào)試非常重要,如果不輸出異常信息,Java檢測(cè)機(jī)制不會(huì)報(bào)錯(cuò),代碼本身也沒(méi)有錯(cuò),這樣會(huì)產(chǎn)生一種情況:當(dāng)代碼出現(xiàn)可以被捕獲的錯(cuò)誤后,無(wú)法知道這種錯(cuò)誤是什么和這種錯(cuò)誤出現(xiàn)的具體位置。所以,本文闡述的插件功能屬于Find Bugs中bad practice一類(lèi)。
本文設(shè)計(jì)中,使用了Hashmap數(shù)據(jù)結(jié)構(gòu),Hashmap用來(lái)存儲(chǔ)鍵值對(duì),key值為Java源代碼中的方法名稱,而value值則為byte code中象征catch內(nèi)容為空的標(biāo)志關(guān)鍵字。例如,本文中我們將要存儲(chǔ)的方法名或關(guān)鍵字用形參mName(方法的名稱)來(lái)代替,對(duì)應(yīng)在字節(jié)碼中相應(yīng)的value有不同的值,我們用統(tǒng)一的形參seen代替,實(shí)現(xiàn)語(yǔ)句如下:
正常情況下的程序,也就是有異常但catch塊不為空,被處理的情況下的字節(jié)碼如下:
對(duì)比以上兩段代碼可以觀察到,第一段中的第11行astore_1將byteArray調(diào)用完成后直接返回,沒(méi)有經(jīng)過(guò)異常處理機(jī)制,即未經(jīng)過(guò)catch塊。第二段中第8行經(jīng)過(guò)astore_1后,進(jìn)行了異常處理函數(shù)的調(diào)用,其指令為第11行的invokevitual。所以,這將成為我們檢測(cè)空的catch塊的一種實(shí)施方案。部分源代碼如下:
由于Find Bugs是一款靜態(tài)分析工具,并且集成了不同檢測(cè)功能的插件,所以要想將本文中的功能集成到Find Bugs中去,最好的辦法就是應(yīng)用visitor設(shè)計(jì)模式。
Visitor模式的主要作用就是在不改變現(xiàn)有類(lèi)的情況下,向其中添加新的方法。其序列圖如下:
圖2 visitor設(shè)計(jì)模式的序列圖
具體實(shí)現(xiàn)的部分源代碼如下:
完成插件的開(kāi)發(fā)后會(huì)生成.jar文件,把.jar文件添加到Find Bugs插件中,再次重啟Eclipse可以看到在Find Bugs中已有新添加的插件。將Find Bugs新的插件應(yīng)用在測(cè)試用例上會(huì)看到,新的插件給出了錯(cuò)誤的具體位置以及錯(cuò)誤信息,如下圖:
圖3 新插件運(yùn)行在測(cè)試用例中的效果
整個(gè)過(guò)程用時(shí)1.15s,可以說(shuō)是比較快,如果和其他插件功能同時(shí)運(yùn)行,基本上不會(huì)增加Find Bugs的運(yùn)行負(fù)擔(dān)。
本文介紹了基于Eclipse的Find Bugs插件的開(kāi)發(fā),重點(diǎn)介紹了對(duì)檢測(cè)空的catch塊功能的研究與開(kāi)發(fā)。由于Eclipse是一款開(kāi)源平臺(tái),所有基于Eclipse插件的開(kāi)放性為廣大的開(kāi)發(fā)者提供了良好的開(kāi)發(fā)平臺(tái),使開(kāi)發(fā)者可以在遵循JVM規(guī)則的基礎(chǔ)之上,對(duì)必要的以及感興趣的功能做嘗試性開(kāi)發(fā)。本文就是在充分了解JVM規(guī)則、Find Bugs運(yùn)行機(jī)制以及已存在的Find Bugs插件基礎(chǔ)上,對(duì)Find Bugs中檢測(cè)空catch塊的功能進(jìn)行了彌補(bǔ)和嘗試性的開(kāi)發(fā),并得到了預(yù)期的效果。