硬體輔助的 AddressSanitizer

如要瞭解如何讀取 HWASan 當機情形,請參閱「瞭解 HWASan 報告」。

Hardware-assisted AddressSanitizer (HWASan) 是一款與 AddressSanitizer 相似的記憶體錯誤偵測工具。相較於 ASan,HWASan 使用 RAM 的量大幅減少,因此非常適合用於整個系統的消毒作業。HWASan 僅適用於 Android 10 以上版本,且僅適用於 AArch64 硬體。

雖然 HWASan 主要用於 C/C++ 程式碼,但也可以協助偵錯會導致 C/C++ 在實作 Java 介面時發生當機的 Java 程式碼。這項工具可以在發生記憶體錯誤時擷取,讓您直接找到相關程式碼,因此非常實用。

您可以從 ci.android.com 將預先建構的 HWASan 映像檔刷新至支援的 Pixel 裝置 (詳細設定操作說明)。

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

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

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

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

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

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

實作詳細資料和限制

HWASan 是以記憶體標記方法為基礎,其中小型隨機標記值會與指標和記憶體位址範圍建立關聯。指標和記憶體標記必須相符,記憶體存取權才能有效。HWASan 會使用 ARMv8 功能的 Top Byte Ignore (TBI),也稱為虛擬位址標記,在位址最高位元中儲存指標標記。

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

在設計上,HWASan 沒有 ASan 用來偵測溢位的有限大小紅區,或 ASan 的有限容量隔離區 (用於偵測釋放後的使用情況)。因此,無論溢位大小為何或記憶體釋放時間有多久,HWAsan 都能偵測到錯誤。與 ASan 相比,HWASan 具備極大的優勢。

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

需求條件

Android 通用核心的最新版本 (4.14 以上) 支援即時啟用的 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 的使用者來說,許多建構複雜性都已消失:

  • 無須執行兩次。
  • 漸進式建構作業可立即使用。
  • 不需更新使用者資料。

部分 AddressSanitizer 限制也會一併移除:

  • 支援靜態執行檔。
  • 您可以略過 libc 以外的任何目標清理作業。與 ASan 不同的是,如果程式庫經過消毒處理,則連結該程式庫的任何可執行檔不一定要經過消毒處理。

您可以自由切換相同 (或更高) 版本號碼的 HWASan 和一般映像檔。無須清除裝置。

如要略過模組的清理程序,請使用 LOCAL_NOSANITIZE := hwaddress (Android.mk) 或 sanitize: { hwaddress: false } (Android.bp)。

清理個別目標

只要 libc.so 也經過消毒,就可以在一般 (未消毒) 版本中為每個目標啟用 HWASan。在 bionic/libc/Android.bp 中的 "libc_defaults" 中,將 hwaddress: true 新增至 sanitize 區塊。然後在您要使用的目標中執行相同動作。

請注意,清理 libc 會啟用系統層級堆積記憶體分配的標記,以及 libc.so 內記憶體作業的標記檢查。即使在未啟用 HWASan 的二進位檔中,如果 libc.so 有錯誤的記憶體存取行為,這項功能也可能會偵測到錯誤 (例如 pthread_mutex_unlock()delete()ed 互斥鎖上)。

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

閃電所

為了進行開發作業,您可以使用 Flashstation,將支援 HWASan 的 Android 開放原始碼計畫版本刷新至 Pixel 裝置,且該裝置已解鎖系統啟動載入程式。選取 _hwasan 目標,例如 aosp_flame_hwasan-userdebug。如需詳細資訊,請參閱應用程式開發人員的 NDK 說明文件,瞭解 HWASan 的相關資訊。

更完善的堆疊追蹤

HWASan 會使用快速的框架指標型解開器,為程式中的每個記憶體配置和取消配置事件記錄堆疊追蹤。Android 預設會在 AArch64 程式碼中啟用影格指標,因此在實際操作中運作良好。如果您需要透過受管理的程式碼解開,請在程序環境中設定 HWASAN_OPTIONS=fast_unwind_on_malloc=0。請注意,不良記憶體存取堆疊追蹤預設會使用「慢速」解開器;這項設定只會影響配置和取消配置追蹤記錄。視負載量而定,這個選項可能會耗用大量 CPU 資源。

符號化

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

應用程式中的 HWASan

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

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