<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統 > 設計應用 > 嵌入式實時應用的高級動態代碼分析(ADCA)

          嵌入式實時應用的高級動態代碼分析(ADCA)

          —— 一種自動檢測C/C++代碼中內存訪問錯誤的方法
          作者:Stephan Lauterbach(勞特巴赫技術公司CTO)時間:2023-09-14來源:電子產品世界收藏

          C 和C++ 程序語言功能強大,但也容易出現錯誤。其中一類容易出現的是內存訪問錯誤,例如緩沖區溢出、內存泄漏等,其后果也可能是災難性的。領先的調試器供應商Lauterbach 希望通過一項名為(Advanced Dynamic Code Analysis ,簡稱)的新技術來幫助嵌入式開發人員避免這類錯誤。

          本文引用地址:http://www.ex-cimer.com/article/202309/450588.htm

          1 引言

          軟件錯誤的代價可能是巨大的,甚至具有災難性后果。例如,1996 年歐洲航天局(ESA)的阿麗亞娜5 號火箭在飛行39 秒后爆炸,造成超過3.7 億美元的損失[1]。事故原因是內部慣性參考系統(SRI)軟件異常,由于執行從64 位浮點數到16 位有符號整數值的數據轉換時,浮點數的值超出了16 位有符號整數所能表示的范圍,導致操作數錯誤。而數據轉換指令(在Ada 代碼中)也沒有保護機制以防止操作數錯誤。

          錯誤發生在控制捆綁式慣性平臺對準的軟件部分。操作數錯誤是由于內部對準函數結果(稱為BH(水平偏差))的值太高引起的,該值與平臺感知的水平速度有關。雖然阿麗亞娜5 號使用的SRI 設計與阿麗亞娜4號幾乎相同,但由于阿麗亞娜5 號早期軌跡與阿麗亞娜4 號不同,導致水平速度值顯著增加,使BH 值比預期高得多。這類錯誤不僅在火箭這一類的項目中可能造成災難性后果,在日常嵌入式系統中也可能是危險的主要來源。

          在1985 年至1987 年間,醫療行業發生了一起嚴重事故。由于多任務系統中存在競爭條件(Race Conditions),Therac-25 放射治療機造成了大量輻射過量,導致三名患者死亡,至少三名其他患者受到嚴重傷害[2]。操作員原本打算使用低功率光束進行治療,但由于沒有放置擴散磁鐵,實際使用的卻是高功率光束,導致劑量遠遠超出預期。這一問題源自代碼庫中的競爭條件(Race Conditions),這種競爭條件在前一個模型Therac-20中就已經存在,但被硬件安全控制所阻止。整個軟件系統由多個同時運行的進程組成,數據輸入和鍵盤處理程序共享一個變量來標識數據輸入是否完成。在數據輸入階段完成后,系統會進入磁鐵設置階段。但是,如果在這8 秒鐘的磁鐵設置階段內,用戶在數據輸入階段使用了特定的編輯序列,由于標識變量的值的影響,設置無法應用到機器硬件上。

          在汽車行業,自動駕駛汽車中的軟件錯誤也造成了多起死亡事故。例如,在2016 年,一輛汽車的傳感器系統未能識別出一輛大型白色18 輪卡車/ 拖車正在穿過高速公路,汽車以全速駛入了拖車的下方[3]。

          為了盡可能避免這類錯誤,自動代碼分析工具可以幫助開發人員自動檢測日益復雜的軟件中的錯誤。

          2 最危險的軟件缺陷

          2.1 內存訪問錯誤是軟件錯誤的主要來源之一

          美國國家網絡安全卓越中心每年都會發布常見缺陷列表(CWE?),其中包括《Top 25 最危險軟件缺陷》(CWE? Top 25)[4]。該清單展示了目前最常見和影響最大的軟件缺陷。

          為了創建這份清單,CWE 團隊利用了國家標準技術研究所(NIST)國家漏洞數據庫(NVD)中的常見漏洞和暴露(CVE?)數據和與每個CVE 記錄相關的常見漏洞評分系統(CVSS)的分數,包括關注網絡安全和基礎設施安全局(CISA)已知被利用漏洞(KEV)目錄中的CVE 記錄。應用了一個公式來根據普遍性和嚴重性對每個軟件缺陷進行評分。

          用于計算2022 年Top 25 的數據集包含了前兩年內共37,899 條CVE 記錄。2022 年,前11 大缺陷中有4個是與內存相關的錯誤( 圖1)。

          image.png

          圖1 2022 CWE? Top 25

          2.2 C/C++語言中典型的內存訪問錯誤

          在2022 年,前11 種軟件缺陷中有四個與內存訪問錯誤有關,如圖2 所示。越界錯誤位居2022 年CWE?Top 25 清單之首。該錯誤類型一般有三種變體,但基本問題的核心都相同:程序在分配的內存區域外寫入或讀取了數據。

          1694672244473437.png

          圖2 三種常見越界示例

          當數據大小超過所分配的內存區域時,可能會發生緩沖區溢出。這種情況下,數據可能被寫入或讀取錯誤的內存位置。此外,當程序計算數據大小或位置不正確時也可能發生緩沖區溢出。在我們的示例中,緩沖區溢出發生在程序試圖訪問數組中無效索引的情況下,即索引小于0 或等于或大于數組長度。

          錯誤,每種錯誤發生的頻率都較低,但其影響也同樣嚴重,主要包括以下幾種。

          ●   未定義行為:程序的行為沒有被編程語言規范所定義。未定義行為的例子包括有符號整數溢出、空指針引用、在沒有序列點的表達式中多次修改同一個標量以及通過不同類型的指針訪問對象。

          ●   內存泄漏:當程序員分配內存但忘記使用delete()函數或delete[] 運算符釋放內存時,就會發生內存泄漏。C++ 中最常見的內存泄漏是使用錯誤的delete 運算符。delete 運算符應用于釋放單個分配的內存空間,而delete [] 運算符應用于釋放數據值數組。

          ●   使用后釋放:當在釋放內存后又引用內存時,會發生這種錯誤。使用先前釋放的內存可能會產生各種不利后果,從有效數據損壞到執行任意代碼,具體取決于缺陷的實例和時序。

          ●   未初始化內存讀?。喝绻麘贸绦驈奈幢惶畛涑跏贾档目蓪ぶ穬却嬷凶x取,則會發生此錯誤。錯誤可能是由于初始化順序不正確或多線程應用程序中的競爭條件引起的。

          ●   返回后使用棧:如果在聲明函數返回后訪問棧變量內存,則會發生此錯誤。

          圖3 列舉了這些錯誤類型的簡短代碼示例。

          1694672334732344.png

          圖3 C/C++代碼中常見內存錯誤

          3 目前可用的自動代碼分析工具

          為了避免C/C++ 代碼中出現內存錯誤,已經有一些動態代碼分析工具可以幫助檢查,如圖4 中顯示是最著名并長期被使用的Valgrind 和AddressSanitizer(簡稱ASan)兩個工具。兩者都支持多種CPU 架構,并以不同方式對代碼進行檢測。但是,由于這兩種工具都會導致性能降低和內存損耗,因此它們在中的使用受到極大的限制。

          1694672386513802.png

          圖4 兩款常用工具比較

          3.1 Valgrind

          Valgrind本質上是一種使用即時編譯技術的虛擬機,包括動態重新編譯[5]。它首先將程序轉換為一種臨時、更簡單的形式,稱為中間表示(IR),然后工具可以自由地對IR 進行任何轉換,最后Valgrind 將IR 轉換成機器代碼并讓主處理器運行它。

          Valgrind 附帶了多個工具, 默認且最常用的是Memcheck。Memcheck 在幾乎所有指令周圍插入額外的檢測代碼,用于跟蹤數據的有效性和可尋址性。此外,Memcheck 用自己的實現替換了標準C 內存分配函數,該實現還包括在所有分配塊周圍設置內存保護。這個功能使Memcheck 能夠檢測到微量偏差錯誤。

          Memcheck 能夠檢測并警告的問題包括以下幾點:

          ●   使用未初始化的內存;

          ●   在內存被釋放后讀寫;

          ●   越界訪問malloc 分配的內存塊;

          ●   內存泄漏。

          使用Valgrind 工具的主要代價是性能的損失。在Memcheck 下運行的程序通常比在Valgrind 外運行慢20-30 倍,并且使用更多的內存(每次分配都會有一定的內存開銷)。

          3.2 ASan

          AddressSanitizer(或ASan)是谷歌安全研究人員創建的一種開源編程工具,用于識別C 和C++ 程序中的內存訪問問題[6]。它可以檢測到內存相關錯誤,例如緩沖區溢出或對懸空指針(釋放后使用)的訪問等。AddressSanitizer 的實現是基于編譯器插樁和直接映射影子內存。

          為了監控內存分配并識別內存泄漏,malloc 和free系列函數被替換,因此每次內存分配/ 釋放都會被工具監控。然后,每次讀取或寫入內存訪問都會被編譯為一段代碼,用來檢查該內存地址是否被標記為有害。如果是有害的,它將報告一個錯誤。

          通常情況下,應用程序的虛擬地址空間被劃分為應用程序代碼使用的程序內存和存儲有害(不可尋址)內存元數據內存的影子內存。 AddressSanitizer 將每8 字節的應用程序內存映射到1 字節的影子內存中。如果一個內存地址未被標識有害(即可尋址),則影子內存中的標志位為0。如果一個內存地址為有害(即不可尋址),則影子內存中的標志位為1。這樣,AddressSanitizer 就可以識別哪些內存訪問是允許的,哪些不允許并報告錯誤。與Valgrind 一樣,您也必須為ASan付出高昂的代價,包括速度損失和內存需求。在Asan 下運行的程序通常比在外部運行慢2 倍,并且平均使用240%更多的內存。

          4 適用于嵌入式實時系統的Lauterbach跟蹤技術

          鑒于現有工具有時無法滿足實時系統的需求,那么使用Lauterbach 的跟蹤技術或者是一種選擇。圖5 顯示了“Lauterbach Trace Pyramid”的功能模塊,頂部是新的 技術。 基于Lauterbach 的上下文跟蹤系統(CTS),而CTS 又基于標準實時流跟蹤技術。

          1694672565864937.png

          圖5 “Lauterbach Trace Pyramid”架構

          4.1 實時流數據跟蹤Real Time Flow Trace

          不斷提高的集成密度和價格壓力導致許多處理器將CPU 內核、緩存、外設、FLASH 和RAM 內存集成在一個封裝中(SoC),在許多情況下甚至不再具有外部存儲器接口。除了調試接口外,很多芯片廠商還在芯片上實現了具有特殊功能的跟蹤接口。這使得程序和數據以壓縮形式可以輸出到芯片外部(圖6),這種方法稱為流跟蹤方法。

          跟蹤總線鏈接到跟蹤接口,通過該總線以壓縮形式傳輸程序流和(或)數據訪問信息。地址總線/ 數據總線的信息在CPU 核心處也可以直接輸出。這意味著也可以記錄對芯片內部FLASH或RAM內存(特別是緩存)的訪問。

          只有少數跟蹤接口支持特定的開/ 關切換或定義地址窗口,以控制生成跟蹤數據。因此唯一的解決方案是使用具有大型跟蹤內存的跟蹤工具,其中所有跟蹤數據都未經過濾地被記錄起來。通過幾秒鐘的錄制時間,很可能可以在錄制數據中找到所尋求的錯誤。此外,多任務程序運行的跟蹤數據也可用于運行時統計分析和/ 或代碼覆蓋率分析。

          這種跟蹤技術唯一的缺點是帶寬問題,即如果芯片內部生成的跟蹤數據比通過跟蹤接口傳輸的更多,就會出數據丟失的情況。芯片制造商一般用FIFO 緩沖區和減少跟蹤數據來解決這個問題。

          實時流跟蹤雖然不是特別高尖端學科,但是,Lauterbach 的跟蹤工具提供了業界最高的數據帶寬和最豐富的數據分析功能。

          1694672677290939.png

          圖6 流跟蹤的通用配置

          4.2 TRACE32上下文跟蹤系統(CTS)

          僅依靠流跟蹤數據可能需要花費大量時間分析跟蹤數據,以找出哪些指令、數據或系統狀態導致目標系統出現故障。

          Lauterbach 的基于跟蹤的調試- 簡稱CTS- 允許用戶根據跟蹤緩沖區中采樣的跟蹤數據重構選定點的目標系統狀態(圖7)。并且從這個選定點開始,可以重復在TRACE32 PowerView GUI 中調試實時記錄在跟蹤存儲器中的程序步驟。執行全功能跟蹤調試的前提條件是將程序和數據流完整記錄到跟蹤緩沖區,直到程序執行停止。

          1694672736862482.png

          圖7 Context Tracking System (CTS)功能

          使能上下文跟蹤系統(CTS)功能后,可以選擇一個記錄點,在指令集模擬器(SIM) 中為其重構目標系統狀態。程序計數器(PC) 自動設置在源程序中對應的位置,即該記錄點所跟蹤數據的地址。

          現在CTS 也已經支持所有調試命令,例如Step、Step Over Call、Go、Return 等。 CPU 指令按照它們在跟蹤存儲器中記錄的順序進行處理。調試功能也實現了進一步擴展,甚至可支持程序向后步進。

          由于指令集模擬器(SIM)支持單個指令的執行,因此也能夠跟蹤變量、內存和寄存器的變化等。甚至T32 SW 還可以自動修復由于跟蹤端口帶寬限制,所產生跟蹤數據遺漏而導致的代碼丟失。如果只采樣讀操作以防止跟蹤端口過載,則CTS 也可以重建所有寫操作。

          此外,TRACE32? 也可以使用CTS 技術支持緩存(Cache)狀態/ 使用率分析等,該技術也是基于跟蹤記錄中捕獲的程序跟蹤數據。如果設置了MMU 架構,則緩存分析將考慮對緩存控制寄存器的所有操作:包括緩存刷新、緩存的開啟和關閉以及緩存鎖定等。

          總之,Lauterbach 的CTS 可以大大簡化調試,特別是對于僅靠停止調試模式往往不夠的實時應用程序。

          4.3 TRACE32 (Advanced Dynamic Code Analysis ,ADCA)

          ADCA 是一種先進的CTS 模式,用于探索和修復由不同類型的錯誤觸發的內存訪問錯誤。它在啟動代碼之后運行,捕獲有效的初始內存和寄存器狀態,堆棧和數據等。

          ADCA 需要完整的程序跟蹤流和足夠的數據來重建所有指針以及從啟動代碼的完整跟蹤數據。該工具還依賴于編譯器提供的正確和完整的調試信息,并需要理解編譯器生成和優化的結構。此外,它還需要理解特殊代碼,如中斷和RTOS 任務切換等。

          ADCA 的核心功能是將靜態和動態標簽分配給所有數據和內存地址。標簽是不可見的元信息,由調試器支持。根據鑰匙鎖原理檢測內存違規:具有某個標簽的數據只能訪問與相同標簽關聯的內存地址(圖8)。

          1694672848554055.png

          圖8 一對一鑰匙鎖校驗機制

          運行程序并記錄跟蹤數據后,您可以運行ADCA功能并結合TRACE32?PowerView 軟件的其他相關窗口的信息,識別相關錯誤(圖9)。

          1694672879695858.png

          圖9 TRACE32 PowerView相關窗口

          Lauterbach 的ADCA 報告顯示了所有潛在內存訪問錯誤的總結( 圖10)。下面將討論報告中的一個具體示例: 訪問名為“check_array1”的數組以及訪問沖突的內存地址(0x418f5c) 時失敗。開發人員可以使用這些信息來分析代碼,并通過使用TRACE32?PowerView GUI中顯示的附加信息來修復錯誤。

          1694672952387739.png

          圖10 TRACE32? ACDA 自動檢測內存錯誤

          從圖9 所示的可能性中,第一個可能的TRACE32?PowerView視圖應該是存儲器顯示( 圖11)。在顯示器的左側,可以觀察到地址418F5C 的標簽變化。結果很明顯,與數組“check_array1”( 標簽28A) 相關的最新有效內存地址是418F5B。

          1694672985682842.png

          圖11 TRACE32? ADCA 內存視圖

          在內存顯示的中間部分可以觀察到,“check_array1”的最高有效索引( 與內存地址418F58 到418F5B 和標簽28A 相關聯) 是“9”。

          正如稍后將看到的,這些信息對于錯誤檢測很有價值,但當然還不足以修復錯誤。

          接下來要探索的是寄存器顯示(如圖12)。顯然,寄存器R1 與標簽28A 相關聯,該標簽屬于數組“check_array1”。不幸的是,R1 指向內存地址418F5C,該地址位于“check_array1”的有效地址空間之外。此時,錯誤的原因已經接近被發現,只需要找出源代碼窗口即可(如圖13)。

          1694673067603810.png

          圖12 TRACE32? ADCA寄存器視圖

          根據寄存器顯示中的信息(如圖12),可以輕松確定寄存器R1 包含Lauterbach 的ADCA 在開始時探索到的對“check_array1 [i]”進行寫訪問的(無效)內存地址。根據內存顯示中的信息,這種無效訪問的原因是顯而易見的:索引變量“i”從0 增加到10,這導致最后一個循環通過“check_array1 [10]”發生內存訪問違規。要修復錯誤,您只需將代碼從“i<11”更改為“i <10”即可。

          1694673100682024.png

          圖13 TRACE32? ADCA源碼視圖

          盡管目前已經有一些成熟的代碼分析工具,但它們卻都不適用于實時的嵌入式軟件應用。而Lauterbach 恰恰滿足了嵌入式開發人員對于實時性的要求和檢測C / C++ 中相關的潛在內存訪問錯誤的需求。ADCA 是識別這些難以發現和復現的錯誤的重大進步,也可支持多核架構。當然也有一些限制。比如某些特殊的結構和錯誤類型無法檢測。但是,這些類型的錯誤通常都會被編譯器檢測出來。特殊的代碼結構可能需要額外的設置來提供分析信息。

          Lauterbach ADCA 技術將在2023 年的軟件版本中作為TRACE32?PowerView 軟件更新的一部分對勞特巴赫客戶免費提供。ADCA 也不會作為單獨產品出售,因此也無法用作第三方跟蹤工具的附加組件。希望這個功能為您的軟件開發提供更多幫助。

          參考文獻:

          [1] https://www.bugsnag.com/blog/bug-day-ariane-5-disaster, Retrieved 12 Feb 2023.

          [2] https://pvs-studio.com/en/blog/posts/0438/, Retrieved12 Feb 2023.

          [3] https://www.businessinsider.com/details-aboutthe-fatal-tesla-autopilot-accident-released-2017-6,Retrieved 12 Feb 2023.

          [4] https://cwe.mitre.org/top25/archive/2022/2022_cwe_top25.html, Retrieved 12 Feb 2023.

          [5] https://valgrind.org/docs/manual/mc-manual.html,Retrieved 12 Feb 2023.

          [6] https://clang.llvm.org/docs/AddressSanitizer.html,Retrieved 12 Feb 2023.

          作者簡介:

          1694673865321202.png

          Lauterbach GmbH公司的所有者之一。自1982年加入勞特巴赫以來,一直在TRACE32調試器產品的開發中處于核心位置,他對復雜的軟硬件系統研發經驗豐富。

          (本文來源于EEPW 2023年9月期)



          評論


          技術專區

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();