靜態分析工具正越來越多地集成到軟件開發過程中。在過程中保存來自編譯器的數據、更改歷史記錄和錯誤信息,而不是作為后置代碼步驟,可以提高靜態分析的效率。
高級靜態分析工具在嵌入式系統開發中變得越來越重要。遠遠超出實際上是編碼風格檢查器的舊靜態分析工具,新工具靜態分析源程序的控制和數據流,從而檢測錯誤和漏洞,例如潛在的緩沖區溢出、未初始化變量的使用、通過空指針訪問,以及對安全攻擊(SQL 注入、跨站點腳本等)的敏感性。
然而,這些先進的工具提出了幾個問題。首先,工具需要了解被分析程序的語義——也就是說,它們必須編譯程序——以執行所需的控制和數據流分析。為此,它們必須緊密集成到構建環境中,以便在編譯時識別和使用所有可能需要的包含文件或其他規范模塊。其次,這些高級工具產生的輸出量可能令人望而生畏,每條診斷信息都需要仔細審查,以確定它是否反映了一個真正的問題,如果是,如何解決它。
將靜態分析工具與軟件開發工具鏈更緊密地集成可以緩解這兩個挑戰。在第一種情況下,將靜態分析工具與編譯器緊密集成在很大程度上消除了構建環境問題,并使用戶界面變得簡單和熟悉。在第二種情況下,可以通過將所有輸出存儲在歷史數據庫中來管理大量輸出,從而允許程序員專注于已知良好版本和源當前狀態之間的增量,而不是在每一步處理所有消息。
與編譯器集成
超越簡單語法檢查的靜態分析工具通常需要編譯器前端的大部分功能,以便它可以根據程序的語義進行分析。這是因為相同的句法形式通常可以根據其成分的含義有不同的解釋。例如,Ada 中的表達式 F(N) 可能(除其他外)是數組引用、函數調用或類型轉換。
訪問程序的底層語義允許該工具跟隨程序中出現的每個名稱回到引入該名稱的聲明,即使存在重載、通用模板或重命名也是如此。該工具將知道每個對象和每個表達式的類型,并將識別任何隱式運行時檢查發生的位置。這些隱式運行時檢查可能包括對取消引用空指針的檢查和對數組邊界之外的索引的檢查。即使沒有隱式運行時檢查的語言也可以將某些運行時操作定義為具有未指定的語義,例如整數算術溢出或超出范圍的數組索引。靜態分析工具需要知道語言語義何時允許這種未指定(因此不可預測)的行為。
由于需要包含編譯器前端的強大功能,許多靜態分析工具都建立在感興趣的語言的現有編譯器技術之上。不幸的是,該工具的構建者選擇的編譯器技術可能與該工具的客戶使用的編譯器無關。發生這種情況時,靜態分析工具可能無法處理客戶編寫的代碼。
例如,如果客戶程序使用編譯器特定的功能(例如中斷處理或特殊的內存映射工具),則無法保證靜態分析工具的底層完全或以同樣的方式支持它們。編譯器前端技術。即使對于可移植代碼,客戶的編譯器和靜態分析工具的底層技術也可能存在不同的錯誤或對語言規則的細微不同的解釋。即使解釋匹配,編譯程序的命令(控制源代碼搜索路徑、預處理器支持和其他功能的命令行開關)也可能有很大不同。因此,復雜程序的構建過程可能難以轉換為對程序執行靜態分析的生成過程。
為了解決這些問題,明確的解決方案是將高級靜態分析引擎與客戶使用的相同編譯器技術集成。因此,靜態分析引擎必須在某種程度上獨立于任何特定編譯器技術使用的中間表示,以便該工具可以輕松地適應支持多個編譯器前端。
一種方法是讓靜態分析引擎擁有自己的中間表示,專門設計用于支持工具執行的高級分析。適應支持新的編譯器前端需要編寫一個轉換模塊,將編譯器的中間表示(前端的輸出)轉換為靜態分析引擎使用的程序表示。翻譯模塊將結果輸出到文件中供以后使用。中間語言翻譯器既可以鏈接到編譯器前端,也可以作為獨立程序運行,讀取編譯器的中間表示,轉換它,然后寫出分析引擎的中間表示。這個過程如圖 1 所示。
圖 1:中間語言翻譯器讀取編譯器的中間表示,對其進行轉換,然后寫出靜態分析引擎的中間表示。
當采用這種集成方法時,靜態分析只是構建過程的另一部分,可以在編譯期間執行,或者為了利用整個程序分析,在鏈接步驟期間執行。對用戶的一個關鍵優勢是調用靜態分析工具只涉及向編譯器和/或鏈接器提供額外的命令行開關。無需為該工具創建專門的構建腳本或維護兩組源(一組與編譯器一起使用,另一組與靜態分析工具一起使用)。
與開發環境集成
由于軟件開發通常通過 Eclipse 等圖形集成開發環境 (IDE) 進行,因此將靜態分析工具和編譯器集成到 IDE 中是很自然的。然后,程序員將立即熟悉該工具的整體界面,從而減少學習曲線并增加定期使用該工具的可能性。
靜態分析工具生成的消息必須像編譯器生成的錯誤或警告消息一樣處理,并由用戶以相同的方式管理和查看。鑒于正在使用多個 IDE,每個 IDE 都有自己的消息格式,靜態分析工具將需要表示其消息,以便可以輕松地將它們轉換為 IDE 期望的任何格式。
消息表示的自然選擇是 XML,因為它使用標記的、自描述的方法來捕獲消息特征。使用 XML 的一個附帶好處是它有助于簡化應用程序的國際化過程,從而可以以客戶喜歡的自然語言顯示消息。
與歷史數據庫集成
一旦高級靜態分析工具與編譯器和 IDE 集成,下一個問題就是處理此類工具可能提供的大量消息。因為高級靜態分析工具正在尋找可能的運行時邏輯錯誤和安全漏洞,所以它們必須模擬運行時程序的執行(識別一組潛在的執行狀態)并確定在什么條件下可能會達到不期望的狀態。不幸的是,這很少是簡單的“是”或“否”。有許多灰色陰影,其中脆弱性程度取決于工具可能未知或超出其分析能力的因素。
這個問題有時用健全性與精確性來表述。如果一個搜索有問題結構的工具能夠識別出它正在尋找的所有問題(沒有誤報),那么它就被認為是可靠的。但穩健性通常是以犧牲精度為代價的。該工具可能會生成大量誤報,這些誤報是用于識別并非真正問題的警告或錯誤。考慮這個使用類 C 語法的簡單示例:
int k, m, n;
... // Complicated code that assigns a positive value to m
... // and that does not assign to n
if (m《0){
k=n;
...
}
工具可能無法推斷 if 語句上的 m《0 條件為假,因此可能會警告 if 語句的主體引用未初始化的變量 (n)。實際問題恰恰相反:if 語句的主體是永遠不會執行的代碼,有時稱為死代碼或無法訪問的代碼。
工具開發人員必須決定是選擇健全性(確保沒有未被檢測到的實際違規)還是精度(確保所有報告的違規都是真正的錯誤)。當一個工具用于安全關鍵或高安全性系統時,天平就會傾斜。使用此類工具的開發人員必須有信心檢測到所有違規行為。但這引發了前面提到的關于如何處理可能產生的大量誤報的問題。當該工具應用于遺留軟件(在應用靜態分析工具之前開發的代碼)時,這個問題尤其明顯。對于大型應用程序,用戶需要查看的消息數量可能令人望而生畏。
將高級靜態分析工具與歷史數據庫集成,可以有效地使用該工具,最大限度地減少誤報導致的問題,即使對于在使用該工具之前開發的復雜應用程序也是如此。關鍵概念是基線的概念以及該工具突出顯示相對于此類基線的增量的能力。通過在歷史數據庫中記錄每個工具運行的所有結果,該工具可以識別任何兩次運行之間的增量(更改)。
數據變得更有用
為了使分析運行之間的比較有效地進行,消息必須是唯一可識別的,而不涉及特定的行號,可以從源代碼的一個版本切換到另一個版本而無需任何重大更改。識別沒有行號的消息的一種方法是記錄消息的文本(或相應的 XML),以及它出現的函數的名稱,如果消息的文本與同一功能中的一些先前消息。
假設消息使用這個與行號無關的唯一標識符作為關鍵字存儲在數據庫中,那么該工具可以輕松識別給定消息是新消息還是先前生成的消息。這使歷史數據庫的整體大小保持可管理。該工具不需要為工具的所有調用重復存儲所有消息的文本,而只需要存儲給定消息的文本一次,以及該消息出現的工具調用范圍的指示(第一次運行生成消息的位置,以及第一次沒有出現的運行)。
該歷史數據庫使用戶界面可以直接顯示或突出顯示自指定基線以來的新消息。這使得該工具即使在具有大量遺留代碼的大型應用程序上也能有效使用。應用程序的已知良好版本可以通過分析工具作為基線運行。可以分析應用程序的當前開發版本,并將分析此已知良好版本的結果作為基線。那些在開發版本上工作的人可以專注于與他們自已知良好版本以來所做的更改相關的任何消息,而不必費力地處理與遺留代碼相關的消息。最終,可以致力于處理這些積壓的消息,
與歷史數據庫集成的另一個好處是能夠從查看分析結果的用戶那里收集評論。在某些情況下,可能需要對特定消息進行大量調查以了解可能的影響。捕獲這項工作很重要。歷史數據庫是記錄用戶學習內容的自然場所。
另外,如果用戶確定所識別的代碼是安全可靠的,歷史數據庫可以記錄該給定消息應該從后續輸出中被抑制,并且可以記錄抑制該消息的支持理由。或者,如果需要更改識別的代碼,歷史數據庫可以記錄分配給問題的程序故障報告 (PTR) ID,從而允許問題跟蹤系統和分析工具的歷史結果之間的可追溯性。當該工具檢測到具有關聯 PTR ID 的消息消失時,可以將其配置為直接通知問題跟蹤系統可以關閉關聯的 PTR 記錄。自動化關閉 PTR 的過程可以顯著減輕通常負擔過重的質量保證團隊的負擔。
靜態分析作為開發過程的關鍵組成部分
隨著應用程序變得越來越大和越來越復雜,高級靜態分析工具在現代軟件開發中發揮著關鍵作用,它顯著減少了查找可能危及系統可靠性、安全性或安全性的錯誤和漏洞所需的工作量。但許多組織尚未充分利用這些工具,通常是因為將它們納入日常軟件開發過程(構建、回歸測試和其他步驟)可能存在很高的進入障礙。
如前所述,兩個重要的步驟可以減少這種進入障礙:工具與編譯器技術和歷史數據庫的集成。這不僅僅是一個理論上的提議。CodePeer 是由 SofCheck 和 AdaCore 聯合開發的高級靜態分析工具,作為 Ada 的自動代碼審查器。該工具已完全集成到 AdaCore 的 GNAT Pro Ada 開發環境中,并可通過 GNAT Programming Studio IDE 調用。
與編譯器的集成在很大程度上消除了將源代碼移植到分析工具的挑戰。成功編譯源代碼的同一編譯器前端還可以生成高級靜態分析引擎進行更深入分析所需的中間表示。此外,相同的命令行開關、源代碼結構和 make 文件可用于編譯和靜態分析代碼。編譯器前端將自動處理應用程序使用的任何特定于實現的功能。
降低進入壁壘的第二個主要步驟是與歷史數據庫的集成,這使得在大型系統上工作的開發人員可以專注于他們最近的更改,并將審查以前發布的遺留代碼中的問題推遲到更合適的時間。此外,與數據庫的集成允許開發人員記錄審查工具輸出的結果以及決定隱藏消息或將其歸檔為 PTR 的理由。最后,數據庫會自動驗證修復并關閉 PTR。通過這兩個步驟,靜態分析可以成為嵌入式軟件開發人員工具箱中重要且高效的工具。
審核編輯:郭婷
-
嵌入式
+關注
關注
5087文章
19148瀏覽量
306194 -
編譯器
+關注
關注
1文章
1636瀏覽量
49175
發布評論請先 登錄
相關推薦
評論