如何看待靜態代碼分析中的誤報?

 

多年前,靜態代碼分析最大的挑戰是試圖找到更多更有趣的東西來檢查。在90年代初Parasoft最初的CodeWizard產品中,有了根據Scott Meyers的《Effective C++》一書中的項目制定的30多條規則。我喜歡把它看做是「程序員的直覺。我曾經跟Scott提到過這件事,雖然他沒有這樣想過......但這確實讓他笑得很開心。程序員

從那時起,靜態分析研究人員就不斷努力推進能夠檢測的範圍,擴大靜態分析的範圍,識別缺陷而不只僅是一段弱代碼。但它仍然存在誤報的問題。靜態分析改變了用戶的關注點,從硬化代碼,到搜索bug,這是很好的,但如今人們在靜態代碼分析中遇到的最多見的障礙之一是試圖理解他們獲得的結果。編程

雖然人們確實會說「我但願靜態分析能抓住____」(說出你最喜歡的找不到的bug),但更常見的是聽到「哇,個人結果太多了!」或「靜態分析太吵了!」或「靜態分析的誤報太多!」所以,做爲一家軟件測試機構,Parasoft的工做就是繼續爲客戶解決這個問題——繼續提供工具和功能,幫助你梳理獲得的結果,並瞭解哪些問題表明了最大的風險。安全

什麼是靜態分析中的誤報?

在靜態分析中,當靜態分析工具錯誤地報告違反了靜態分析規則時,就會出現「誤報」。固然,這多是主觀的。有時,開發人員會掉進一個陷阱,把任何他們不喜歡的錯誤信息都貼上「誤報」的標籤,但這其實並不正確。在不少狀況下,他們只是不一樣意這個規則,他們不理解這個規則在這種狀況下是如何應用的,或者他們認爲它在通常狀況下(或者在這個特殊狀況下)並不重要。我把這叫作噪音,而不是誤報。我在這裏發現的有趣的事情是,工具越是聰明,就越有可能產生一個開發者乍一看可能不理解的發現。工具

基於模式的分析中的誤報

基於模式的靜態分析實際上並不存在誤報。若是工具報告說某條靜態分析規則被違反了,而實際上並無,這說明規則有bug(由於規則不該該是模棱兩可的)。若是規則沒有明確的模式可尋,這就是一個壞規則。單元測試

我並非說每個被報告的規則違規都表示存在缺陷。違規只是意味着發現了模式,代表代碼的弱點,容易有缺陷。測試

當我看到一個違規行爲時,我會問本身這個規則是否適用於個人代碼。若是適用,我就修復代碼。若是不適用,我就抑制這個違規行爲。最好直接在代碼中壓制靜態分析違規行爲,這樣對團隊成員來講是可見的,並且你最終也不會再去審查第二次。不然,你就會不斷地重複審查一樣的違規行爲;這就像試圖拼寫檢查,但永遠不會在它的字典中添加你的「特殊」單詞同樣。代碼內抑制的好處是,它獨立於靜態分析引擎。任何人均可以查看代碼,並看到代碼已經被審查過,而且這個模式被認爲在這個代碼中是能夠接受的。若是你須要證實符合編碼標準,這一點特別有用。而若是你確實須要符合標準,那麼很容易使用現有的配置來知足這些標準,如CWEMISRAIEC 62304DO-178B/C等。編碼

基於流量的分析中的誤報

對於基於流程的分析,誤報不只是方法所固有的,並且是相關的--須要解決。流程分析沒法避免誤報,緣由與單元測試沒法生成完美的單元測試用例同樣。分析必須對代碼的預期行爲作出判斷。有時選項太多,沒法知道什麼是現實的;有時你根本沒有足夠的信息來了解系統其餘部分的狀況。spa

這裏重要的是,真正的誤報是徹底錯誤的東西。例如,假設你正在使用的靜態分析工具說你正在讀取一個空指針。若是你看了一下代碼,發現這實際上是不可能的,那麼你就有一個誤報。線程

另外一方面,若是你根本不擔憂這段代碼中的空值,由於它們在其餘地方被處理了,那麼這個消息(雖然對你來講並不重要)並非一個誤報。它是真實的,並且剛好是不重要的。流程分析工具的消息從「真實且重要」到「真實且不重要」,從「真實且不可能」到「不真實」。這裏有不少變化,每一個人都應該有不一樣的處理方式。指針

這裏也有一個常見的陷阱。就像上面的null例子同樣,你可能認爲一個null值不可能作到這一點,可是工具找到了一種方法讓它發生。若是它對你的應用很重要,必定要檢查,並可能對此進行保護。

關鍵是要明白,流分析有力量也有弱點。流程分析的強大之處在於,它經過代碼,試圖找到熱點,並圍繞熱點發現問題。弱點是它必須作出假設來嘗試遍歷代碼,並且越是遍歷,越容易產生不可能的路徑。

真正的問題是,若是你開始認爲你已經清理了全部的代碼,由於你的流程分析是乾淨的,你是在欺騙本身。真的,你已經發現了一些錯誤,你應該爲此感到慶幸。沒有流程分析錯誤只是意味着你沒有發現任何東西,而不是說代碼很乾淨。若是你正在構建安全關鍵型軟件,最好確保你使用的是C/C++testdotTESTJtest這樣的工具,它同時具備兩種類型的靜態分析功能。

運行時錯誤檢測

一個很好的,但一般被忽視的補充流分析的方法是運行時錯誤檢測。運行時錯誤檢測能夠幫助你發現比流程分析能檢測到的更復雜的問題,並且你有信心該條件確實發生了。運行時錯誤檢測不會像靜態分析那樣出現誤報。當它發現一個缺陷時,是由於它在執行過程當中實際觀察到了它的發生——不涉及任何假設。

你的運行時規則集應該與靜態分析規則集緊密匹配。這些規則能夠發現相同類型的問題,但運行時分析有大量的執行路徑可供它使用。這是由於在運行時,存根、設置、初始化等都不像流分析那樣成爲問題。惟一的限制是,它只和你的測試套件同樣好,由於它檢查你的測試套件剛好執行的路徑。若是你是用CC++編程,特別是像物聯網這樣的嵌入式設備,能夠看看Insure++——它能夠在運行時找到比其餘任何工具更多的bug。而不是被線程問題、內存泄漏和競賽條件等棘手的問題所困擾,你能夠在運行時準確地找到它們。

值得花時間嗎?

我對待誤報的方法是這樣的。若是要花3天時間來修復一個bug,那還不如花20分鐘去看一個誤報......只要我能夠標記它,永遠不用再看它。這是個正確看待的問題。好比說你的線程有問題。線程的問題是急劇難以發現的。若是你想找到一個與線程有關的問題,你可能要花上幾周的時間去追蹤它。我更但願在寫代碼的時候,首先不能出現問題。換句話說,我試圖將個人過程從檢測轉向預防。

靜態分析,若是部署得當,並不必定是一種嘈雜不愉快的體驗。看看Parasoft是如何以不一樣的方式作事的,特別是使用Parasoft DTP的所有功能,經過智能分析來管理結果,讓你專一於軟件中的風險,而不是追逐不重要的問題。

相關文章
相關標籤/搜索