.NET靜態分析與Parasoft dotTEST

fmms 12年前發布 | 49K 次閱讀 .NET .NET開發

        .NET 中的靜態分析

        如果你想要添加一段以后經常會訪問的代碼,那么能夠得到提醒不是很好嗎——可能是在開發過程中需要花費幾天才能夠找到并修復的 bug,可能是看起來你的團隊成員無法重用和擴展的代碼,或者是能夠影響安全、可靠性和性能的缺陷。

        靜態分析能夠給你這種善意的提醒。. . 并且這確實可以在 .NET 開發中實現。

        什么是靜態分析?

        靜態分析是一個很有趣的術語,就像“網絡管理員(web master)”一樣,可能會擁有多種不同的意思。一種有效的定義是:靜態分析是對計算機軟件執行的一種分析,而不會真正執行要測試的軟件。這個定義讓我們清楚,靜態分析的意義要比我們期望的更廣泛,但是它不包括功能測試之類的內容,所以范圍還是有限的。

        靜態分析所涉及到的內容包括:

  • 代碼美化
  • 同行審查(即手動的代碼審查和代碼檢查)
  • 基于模式的代碼掃描
  • 基于流程的代碼掃描
  • 基于度量的代碼掃描
  • 編譯器以及其它與構建相關的輸出

        本文會討論以上各種技術,以及在何時、何地使用它們,還有為什么它們會對我們有幫助。

        代碼美化

        有時候人們會把靜態分析歸為只是會檢查大括號位置是否合適的一種工具,但我們并不會對此感到奇怪。這種用法對我們還是很有幫助的,但是靜態分析最強大的功能遠遠不止如此。

        同行審查

        同行審查或者手動的代碼審查基于這樣的觀點,同事之間應該互相查看代碼,看它是否完成了應有的功能。

        同行代碼審查是找到代碼缺陷的最有效方法。通過代碼審查,我們平均可以排除 60% 的缺陷(Boehm 和 Basili 所寫的《十種最有效減少軟件缺陷的方法》,Computer, January 2001)。這也并不奇怪,畢竟代碼審查使用的是最好的分析工具:人類的大腦。

        顯然你無法自動化進行同行的代碼審查,但是你可以使用大量的技術,使得同行審查更有效率,也讓你不必一味地對語法之類的低級問題吹毛求疵。例如,你可以自動化檢查這些低級的問題,還可以把代碼審查的準備、通知和跟蹤工作自動化。

        基于模式的分析

        基于模式的分析會定義代碼模式(patterns),它們或者是需要確保出現在你的代碼中,或者需要確保不出現在你的代碼中。

        換句話說,靜態分析可以查找好模式和壞模式。例如,它可以確保我的代碼打印出版權聲明,或者它可以檢查一些格式的問題,像括號放置的位置以及是否區分大小寫等等。這種方法可以幫助團隊檢測 .NET 代碼是否遵守某種規則或者一系列編碼實踐。

        除了能夠找到語法問題之外,模式匹配靜態分析還能夠找到可能導致缺陷的原因。這可能不會顯示出已存在的缺陷,而是告訴你大概的區域。這樣,我們可以使用基于模式的分析來避免錯誤,而這也是真正的生產力和質量提升的關鍵所在。

        如果得到合適地應用,靜態分析不僅可以找到像代碼美觀之類簡單的問題,還能夠幫助開發者識別出潛在的邏輯缺陷,也能夠檢測到 NullReferenceExceptions 和資源泄漏之類的錯誤。

        即便是最基本的靜態分析——檢查代碼是否遵循了業界接受的標準——也能夠立刻暴露出一些問題,而使用單元測試、手動檢查和其他驗證技術可能需要幾個小時。

        重要的是,你應該把靜態分析的代碼標準看成是防止錯誤出現的一種方式,而不是用來檢測錯誤的。如果違背了基于模式靜態分析的地方沒有指向顯而易見的缺陷,很多開發者會對此表示失望。當他們檢查違反規則的代碼,發現的是可能出現錯誤的結構體,而不是真正的錯誤時,就會認為靜態分析規則沒用,甚至停止對違反規則了的代碼的調查,之后甚至停止執行靜態檢查。

        這就涉及到了軟件業界的一個基本問題:大多數開發和測試團隊關心的是移除錯誤,而不是如何避免錯誤。

        讓人驚奇的是,基于模式的靜態分析能夠提高開發者的工作質量。它會監視著開發者的工作,當做事的方式不理想的時候,就會做出提醒。

        例如,一位開發者可能會編寫包含 try/catch 塊的代碼來訪問數據庫,但是忘了使用 finally 塊來釋放資源。使用恰當的靜態分析規則,當他這么寫代碼的時候就會收到提醒,這樣他就能立刻修正。經過幾次這種“提醒”之后,最后開發者就會改變編寫代碼的方式了。

        基于流程的分析

        基于模式的靜態分析會在特定的文件或者類中查找指定的模式,而流程分析會在應用程序中試圖遵循特定的執行路徑來查找模式,而不會真正地運行這些代碼。

        基于流程的工具會模擬應用程序的執行,基于程序邏輯在代碼中尋找可能的執行路徑,甚至可能試圖注入一些壞數據。這樣會找到可能會觸發運行時缺陷的執行路徑,像 NullReferenceExceptions、資源泄漏及 SQL 注入之類的安全缺陷,從而找到應用程序中的真正缺陷。

        當我使用數據流分析來擴展基于模式的靜態分析,并使用自定義的代碼規范對其進一步擴展,它會變得更加強大。創建自定義的標準能夠幫助你完全消除很多非常復雜和重要的錯誤。例如,我們可以使用這些標準暴露你的應用程序所特有的錯誤,像安全缺陷和 API 使用錯誤等。這樣的錯誤通過手動測試或檢查很難發現,并且,如果在正式運行之前沒有檢測到,那么就會變得非常難以修復。

        使用一組整合的靜態分析技術,在軟件開發生命周期的早期就暴露出這些重大的缺陷,會節省大量的診斷和可能返工的時間。

        基于度量(Metrics-based)的分析

        可能最古老的靜態分析就是基于度量的分析了,它會對代碼的各個方面——像復雜度,或者文件的代碼行數和方法個數等——做出度量。

        度量分析想要達成的目的有兩個:理解代碼中的狀況,并找到可能發生的問題。當我們在 20 年前開始做靜態分析的時候,就有很多種度量。我們會使用它們來診斷無法再現的問題,然后使用調試器來調試度量工具所建議的位置。

        基于度量的分析的質量取決于你要查找的是什么。度量對于幫助你從全局了解代碼特別有用。例如,如果你檢查了應用程序文件的代碼行數,并且發現突然出現了巨大的文件,那么你可能就需要對設計做出改進了。組件應該是離散的,擁有已知的輸入,并產生已知的輸出。如果在其中有大量復雜的邏輯,那么這時你就需要查看你的組件,并考慮對它們進行分解了。

        編譯器輸出

        在靜態分析中經常被忽視的內容就是編譯器的輸出。在過去,這些輸出經常會被忽略或者掩蓋,但是對質量和穩定性感興趣的開發者發現,清理編譯器錯誤會防止在運行時出現奇怪的問題。

        下次你看到編譯器錯誤,并且想要忽略的時候,就要考慮一下你是否有足夠的能力編寫自己的編譯器。如果沒有的話,那么就修正錯誤。

        .NET 中的靜態分析

        現在我們已經討論了好幾種靜態分析的方法,接下來讓我們專門討論一下 .NET 中的基于模式和基于流程的分析。Parasoft 已經創建了一種叫做 dotTEST 的工具,它能夠執行靜態分析,當然還有一些其它功能。

        Parasoft dotTEST 會整合在 Visual Studio IDE 中,你可以在 VS 解決方案管理器中選擇項目或者文件,然后在選定的資源上運行 dotTEST 命令。你可以在 VS 中查看分析結果,重新分配和消除錯誤,以及諸如此類的工作。

.NET靜態分析與Parasoft dotTEST        dotTEST 的工作原理

        dotTEST 會通過檢查 IL 代碼和源代碼執行靜態分析。檢查 IL 代碼讓 dotTEST 可以分析所有 .NET 語言編寫的程序,盡管對一些規則的檢查還必須在源代碼級別上執行。

        dotTEST 使用了多種測試技術,像解析 C# 代碼、使用 .NET 反射 API 以及讀取 .NET 程序庫等等。這些技術讓我們可以執行靜態分析、度量分析、流程分析(使用 BugDetective)、單元測試以及生成單元測試等等。

        最先進的 dotTEST 特性在于流程分析,它會創建恰當的控制流圖,并對其進行分析,以找到 NullReferenceExceptions、資源泄漏、不安全的操作以及其它可能出現的異常狀況。

        dotTEST 還能夠計算單元測試的覆蓋率,或者在單元測試的過程中重寫正在執行的 IL 代碼,從而應用 stub,這項操作是在應用程序運行時,將 IL 代碼編譯成本地代碼之前做到的。

        dotTEST 中的基于模式的靜態分析

        dotTEST 中預設置了上百種內建規則——包括微軟的 .NET 框架設計指南中的內容、《Effective C#》 《.NET Gotchas》書中的內容,以及很多公司軟件開發者的經驗。

        在 dotTEST 中預加載了超過 440 項模式規則對;這些規則覆蓋了以下方面:

  • 一般錯誤
  • API 設計
  • API 使用
  • 序列化
  • 國際化
  • 安全
  • Web 應用程序最佳實踐
  • C#最佳實踐
  • 資源泄漏和內存使用

        每項規則都說明了自身的重要性、遵循的好處、不遵循的風險,以及如何修正它所發現的模式。規則的嚴格等級是基于可能造成的破壞預設的,并且可以自定義。規則組還可以針對安全、OWASP、NIST SAMATE 以及 IEC 63204 等情況打包。

        盡管還是存在可以妥協的需求,但檢查代碼是否符合這些規則還是很重要——即便是在這些代碼已經編寫完成之后。

        基于模式的靜態分析——示例

        讓我們假設,基于模式的靜態分析發現有些代碼違反了“避免使用靜態集合”規則。

        這項規則很重要,因為它能夠識別出可能會導致內存泄漏的代碼。靜態集合對象(像 ArrayList 等)能夠保存大量對象,這些對象都可能造成內存泄漏。如果你在“靜態”集合中放置了短期使用的對象,并且忘了刪除,那么在程序繼續運行的時間內,那個對象都會被集合所引用。

        通過 profiling 或者負載測試我們可以發現導致的內存泄漏問題,但是那需要設計和實現測試,然后跟蹤問題到特定的代碼行。使用模式匹配靜態分析工具,我們在幾秒之內就可以自動檢測到這樣的代碼。

        下面的截屏顯示了 dotTEST 的模式匹配靜態分析是如何識別出一種情況,其中開發者想要使用邏輯與操作,而實際上使用的是按位與操作。

.NET靜態分析與Parasoft dotTEST

        由于按位與操作不會報錯,所以即便 ssn 是 null,也會對 ssn 進行計算,這就會導致拋出異常。盡管在簡單情況下這個異常是顯而易見的,但在很多復雜的情況下,我們很可能無法測試出來。

        為了確保過程盡可能有效合理,我們還可以在 Parasoft 的圖形化創建規則界面(RuleWizard)中創建 IL 級別和 C# 級別的規則,從而強迫執行特定的項目和組織的需求,從而避免再次出現特定應用程序中會出現的缺陷。

        規則名稱以及嚴格程度分類可以與你的團隊的內部編碼策略和優先級對應。此外,針對特定情況的抑制(suppression)為我們提供了一種系統方式,它可以在整體上遵循規則,但是做出一些例外,你或者你的團隊認為可以接受它們。

        dotTEST 中的流程分析

        針對基于流程的分析,Parasoft 的 BugDetective 使用了多種分析技術,包括模擬應用程序執行路徑,從而識別出可能觸發運行時缺陷的路徑。可以檢測到的缺陷包括使用空引用異常、除零問題以及資源泄漏。

        示例1

        例如,下面的圖片顯示了 BugDetective 在示例銀行應用程序中找到的三個問題:

.NET靜態分析與Parasoft dotTEST

        讓我們詳細看下如何避免 NullReferenceException 錯誤,你會注意到 BugDetective 顯示了導致該問題的完整執行路徑。

        在這個案例中,在第 64 行 cust 被設置為 null。在第 68 行,又調用了 LookupCustomerName 方法。在那個方法的第 48 行拋出了異常。由紅色的圓點標記。然后控制會轉到 catch 塊,其中在第 74 行發生了空引用。

        這個問題很可能會逃過一般測試的檢查。

        示例2

        這里發現的第二個錯誤又是一種很難重現和調試的缺陷。這個例子在析構函數中使用了托管的資源 resourceCache,并在析構函數中調用了 Changed 方法(圖中未顯示)。這里的問題是,由于垃圾回收程序的固有機制,那時 resourceCache 可能已經被回收了。我們在很多應用程序中都看到過這個問題,毋庸置疑,它會讓程序崩潰。…這經常是在應用程序準備關閉的時候。

.NET靜態分析與Parasoft dotTEST        總結

        靜態分析可以為 .NET 提供很多功能。它可以執行基于模式的規則,不管它們是基于已驗證的標準,還是能夠幫助你識別特定應用程序中缺陷的自定義模式。它可以快速掃描所有代碼,并定位所有違反了你選定的規則集合的高風險代碼。

        盡管如此,這種分析技術還是無法檢測到所有缺陷。很多缺陷是由于不同的方法和類之間的交互導致的,并且依賴于實際的執行路徑。此外,傳統的測試方法(像單元測試和應用程序級的測試)通常找不到這樣的缺陷,因為我們很難重現發生異常的條件。即便達到了 100% 的聲明覆蓋率,還是有很多路徑我們無法覆蓋到。所以,擁有能夠模擬代碼中的大量執行路徑的自動化工具會對我們非常有用,它們能夠找到可能存在的缺陷。

        dotTEST 的流程分析特性所完成的正是這樣的工作。它會模擬可能的執行路徑,從而顯示出可能在運行時發生的缺陷,讓你可以在項目達到那個階段之前就對其采取預防措施。

        把這些強大的方法與執行靜態分析的制度組合在一起,你就擁有了經過驗證的方式來獲得軟件開發的關鍵益處:

  1. 檢測到會影響可靠性、安全性和性能的潛在缺陷。
  2. 執行組織的設計規則和規范(針對特定應用程序、特定用途或者特定平臺)以及從已知的特定缺陷中抽象出來的錯誤預防規則。
  3. 提升類的設計和代碼的組織,從而提高代碼的可維護性。
  4. 應用通用的格式化、命名以及其它樣式約定,提升代碼的可讀性。

        不管在使用 .NET 開發過程中采用的是哪種靜態分析方法,它都會讓你找到導致缺陷的根本原因,消除可能產生缺陷的模式,從而預防缺陷的發生。

        延伸學習

        想要了解更多細節,你可以查看一下資源:

        關于作者

.NET靜態分析與Parasoft dotTEST

        Arthur Hicken是 ParaSoft 的布道師和解決方案架構師,他和公司的高管一起制定戰略決定。他在近 20 年以來一直在 Parasoft 參與自動化各種實踐的工作。他曾經從事過很多項目,包括數據庫開發、軟件開發生命周期、web 發布和監控、軟件構建自動化的各個方面以及與遺留系統整合等等。此外,Hicken 先生還擁有很多其它方面的經驗,包括監管數據庫技術、數據挖掘、數據倉庫、數據集市等等,它還開發了一個高水準的內部數據庫系統。

        Hicken 曾經與多家公司的 IT 部門協作,像 Cisco、Vanguard、Motorola 等等,幫助他們提升軟件開發的實踐。他還在 Parasoft 創建并引領了很多內部技術培訓課程。它還為 Parasoft 的客戶創建并講授了很多培訓課程。作為領域專家,Arthur 的觀點多次被 Business 2.0、Internet Week 以及 CNET news.com 在談到站點質量問題時引用。

        查看英文原文:.NET Static Analysis and Parasoft dotTEST

        來自: InfoQ
 本文由用戶 fmms 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!