硬體輔助的 AddressSanitizer

如要瞭解如何解讀 HWASan 異常終止,請參閱「瞭解 HWASan 報告」一文。

Hardware-assisted AddressSanitizer (HWASan) 是一款與 AddressSanitizer 相似的記憶體錯誤偵測工具。HWASan 使用的 RAM 比 ASan 少很多,因此適合用於全系統清除。HWASan 僅適用於 Android 10 以上版本,且僅適用於 AArch64 硬體。

雖然 HWASan 主要用於 C/C++ 程式碼,但也能協助偵錯 Java 程式碼,這類程式碼會導致用於實作 Java 介面的 C/C++ 發生當機情形。這項功能很有幫助,因為它會在發生記憶體錯誤時偵測到,並直接指出負責的程式碼。

相較於傳統 ASan,HWASan 具備以下特點:

  • 額外占用的 CPU 資源相近 (約 2 倍)
  • 額外占用程式碼的空間相近 (40 - 50%)
  • 額外占用的 RAM 大幅減少 (10% - 35%)

HWASan 能夠偵測 ASan 可偵測到的錯誤:

  • 堆疊和堆積緩衝區溢位/反向溢位
  • 釋放後的堆積使用情況
  • 超出範圍的堆疊使用情況
  • 重複釋放/錯誤釋放

此外,HWASan 還能偵測回傳後的堆疊使用情形。

HWASan (與 ASan 相同) 與 UBSan 相容,兩者可在目標上同時啟用。

實作詳細資料和限制

HWASan 採用記憶體標記方法,將小型隨機標記值與指標和記憶體位址範圍建立關聯。如要讓記憶體存取有效,指標和記憶體標記必須相符。 HWASan 依賴 ARMv8 功能「最高位元組忽略」(TBI),也稱為虛擬位址標記,將指標標記儲存在位址的最高位元中。

如要進一步瞭解 HWASan 的設計,請參閱 Clang 說明文件網站。

根據設計,HWASan 沒有 ASan 的有限大小紅區,因此無法偵測溢位,也沒有 ASan 的有限容量隔離區,因此無法偵測釋放後使用。因此,無論溢位大小或記憶體解除分配的時間長短,HWASan 都能偵測到錯誤。因此 HWASan 比 ASan 更有優勢。

不過,HWASan 的標記值數量有限 (256 個),這表示在程式執行期間,有 0.4% 的機率會遺漏任何錯誤。

需求條件

新版 (4.14 以上) 的常見 Android 核心支援 HWASan,Android 10 專用分支版本不支援 HWASan。

Android 11 開始,使用者空間支援 HWASan。

如果您使用其他核心,HWASan 需要 Linux 核心接受系統呼叫引數中的標記指標。下列上游修補程式集已實作這項支援:

如果您使用自訂工具鍊建構,請確保工具鍊包含 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。在 bionic/libc/Android.bp 的清理區塊中新增 hwaddress: true"libc_defaults"然後在您處理的目標中執行相同操作。

請注意,清理 libc 可在全系統範圍內標記堆積記憶體配置,並檢查 libc.so 內記憶體作業的標記。如果錯誤的記憶體存取位於 libc.so (例如 pthread_mutex_unlock() (在 delete()ed mutex 上)。

如果整個平台都是使用 HWASan 建構,則不需要變更任何建構檔案。

更優質的堆疊追蹤

HWASan 會使用快速的影格指標型解開器,記錄程式中每個記憶體配置和取消配置事件的堆疊追蹤。Android 預設會在 AArch64 程式碼中啟用框架指標,因此這項做法在實務上非常有效。如要透過受管理程式碼解除堆疊,請在程序環境中設定 HWASAN_OPTIONS=fast_unwind_on_malloc=0。請注意,預設情況下,錯誤的記憶體存取堆疊追蹤記錄會使用「慢速」解開器;這項設定只會影響配置和取消配置追蹤記錄。視負載而定,這個選項可能會耗用大量 CPU 資源。

符號化

請參閱「瞭解 HWASan 報告」一文中的「符號化」。

應用程式中的 HWASan

與 AddressSanitizer 類似,HWASan 無法查看 Java 程式碼,但可以偵測 JNI 程式庫中的錯誤。在 Android 14 之前,支援在非 HWASan 裝置上執行 HWASan 應用程式。

在 HWASan 裝置上,應用程式可透過使用 SANITIZE_TARGET:=hwaddress 在 Make 中建構程式碼,或使用編譯器標記中的 -fsanitize=hwaddress,以 HWASan 進行檢查。在非 HWASan 裝置 (搭載 Android 14 以上版本) 上,必須新增 wrap.sh 檔案設定 LD_HWASAN=1。詳情請參閱 應用程式開發人員說明文件