有關如何讀取 HWASan 崩潰的信息,請參閱了解 HWASan 報告!
硬體輔助的 AddressSanitizer (HWASan) 是一種類似AddressSanitizer 的記憶體錯誤偵測工具。與 ASan 相比,HWASan 使用的 RAM 少得多,這使其適合整個系統清理。 HWASan 僅適用於 Android 10 及更高版本,且僅適用於 AArch64 硬體。
雖然 HWASan 主要用於 C/C++ 程式碼,但它也可以幫助調試導致用於實現 Java 介面的 C/C++ 崩潰的 Java 程式碼。它很有用,因為它可以在發生記憶體錯誤時捕獲它們,直接將您指向負責的程式碼。
您可以從ci.android.com將預先建置的 HWASan 映像刷新到支援的 Pixel 裝置(詳細設定說明)。
與經典的 ASan 相比,HWASan 具有:
- 類似的 CPU 開銷 (~2x)
- 類似的程式碼大小開銷 (40 – 50%)
- RAM 開銷小很多 (10% – 35%)
HWASan 偵測到與 ASan 相同的一組錯誤:
- 堆疊和堆疊緩衝區上溢/下溢
- 釋放後的堆使用
- 堆疊在範圍外使用
- 雙自由/狂野自由
此外,HWASan 會在返回後偵測堆疊使用情況。
HWASan(與 ASan 相同)與UBSan相容,兩者可以同時在目標上啟用。
實施細節和限制
HWASan 是基於記憶體標記方法,其中一個小的隨機標記值與指標和記憶體位址範圍相關聯。為了使記憶體存取有效,指標和記憶體標籤必須匹配。 HWASan 依賴 ARMv8 功能頂位元組忽略 (TBI)(也稱為虛擬位址標記)將指標標記儲存在位址的最高位元中。
您可以在 Clang 文件網站上閱讀有關HWASan 設計的更多資訊。
根據設計,HWASan 沒有 ASan 的用於檢測溢出的有限大小的紅區,也沒有 ASan 的用於檢測空閒後使用的有限容量的隔離區。因此,無論溢出有多大或記憶體被釋放多久,HWASan 都可以偵測到錯誤。這使得 HWASan 比 ASan 有很大的優勢。
然而,HWASan 的可能標籤值數量有限 (256),這意味著在程式的一次執行過程中遺漏任何錯誤的機率為 0.4%。
要求
常見 Android 核心的最新版本(4.14+)支援開箱即用的 HWASan。 Android 10 特定分支不支援 HWASan。
從Android 11開始提供對 HWASan 的使用者空間支援。
如果您使用不同的內核,HWASan 要求 Linux 內核接受系統呼叫參數中的標記指標。以下上游補丁集中實現了對此的支援:
- arm64 標記地址 ABI
- arm64:取消標記傳遞給核心的使用者指針
- mm:避免在brk()/mmap()/mremap()中建立虛擬位址別名
- arm64:驗證從核心執行緒呼叫的 access_ok() 中的標記位址
如果您使用自訂工具鏈進行構建,請確保它包含 LLVM 提交c336557f之前的所有內容。
使用 HWASan
使用以下命令使用 HWASan 建立整個平台:
lunch aosp_walleye-userdebug # (or any other product)
export SANITIZE_TARGET=hwaddress
m -j
為了方便起見,您可以將 SANITIZE_TARGET 設定新增至產品定義中,類似於aosp_coral_hwasan 。
對於熟悉 AddressSanitizer 的用戶來說,許多建置複雜性都消失了:
- 無需運行 make 兩次。
- 增量建置開箱即用。
- 無需刷新用戶資料。
一些 AddressSanitizer 限制也消失了:
- 支援靜態可執行檔。
- 可以跳過 libc 以外的任何目標的清理。與 ASan 不同的是,如果一個庫被清理,那麼連結它的任何可執行檔也必須被清理。
可以在相同(或更高)版本號的 HWASan 和常規映像之間自由切換。不需要擦拭設備。
若要跳過模組的清理,請使用LOCAL_NOSANITIZE := hwaddress
(Android.mk) 或sanitize: { hwaddress: false }
(Android.bp)。
清理單一目標
只要libc.so
也經過清理,就可以在常規(未清理)建置中為每個目標啟用 HWASan。將hwaddress: true
加入到 bionic/libc/Android.bp 中"libc_defaults"
的清理區塊中。然後在您正在處理的目標中執行相同的操作。
請注意,清理 libc 可以在系統範圍內標記堆記憶體分配,並檢查libc.so
內記憶體操作的標籤。如果錯誤的記憶體存取位於libc.so
(例如, delete()
pthread_mutex_unlock()
),即使在未啟用 HWASan 的二進位檔案中,這也可能會捕獲錯誤。
如果整個平台是使用 HWASan 建構的,則無需更改任何建置檔案。
快閃記憶體
出於開發目的,您可以使用Flashstation將支援 HWASan 的 AOSP 版本閃存到具有解鎖引導程式的 Pixel 裝置上。選擇_hwasan 目標,例如aosp_flame_hwasan-userdebug。有關更多詳細信息,請參閱適用於應用程式開發人員的 HWASan NDK 文件。
更好的堆疊追蹤
HWASan 使用基於幀指標的快速展開器來記錄程式中每個記憶體分配和釋放事件的堆疊追蹤。 Android 預設在 AArch64 程式碼中啟用幀指針,因此這在實踐中效果很好。如果需要透過託管程式碼展開,請在進程環境中設定HWASAN_OPTIONS=fast_unwind_on_malloc=0
。請注意,錯誤的記憶體存取堆疊追蹤預設使用“慢速”展開器;此設定僅影響分配和釋放追蹤。此選項可能非常佔用 CPU 資源,具體取決於負載。
符號化
請參閱「了解 HWASan 報告」中的符號化。
應用程式中的 HWASan
與 AddressSanitizer 類似,HWASan 無法查看 Java 程式碼,但它可以偵測 JNI 程式庫中的錯誤。在 Android 14 之前,不支援在非 HWASan 裝置上執行 HWASan 應用程式。
在 HWASan 設備上,可以透過在 Make 中使用SANITIZE_TARGET:=hwaddress
或在編譯器標誌中使用-fsanitize=hwaddress
建立程式碼來使用 HWASan 檢查應用程式。在非 HWASan 裝置(執行 Android 14 或更高版本)上,必須新增wrapp.sh 檔案設定LD_HWASAN=1
。有關更多詳細信息,請參閱應用程式開發人員文件。