從 NDK r21 和 Android 10 (API 級別 29) 開始,Android NDK 支援 HWAddress Sanitizer (又稱為 HWASan)。HWASan 僅適用於 64 位元 Arm 裝置。
HWASan 是一款與 ASan 相似的記憶體錯誤偵測工具。相較於傳統 ASan,HWASan 具備以下特點:
- 額外占用的 CPU 資源相近 (約 2 倍)
- 額外占用程式碼的空間相近 (40 - 50%)
- 額外占用的 RAM 大幅減少 (10% - 35%)
HWASan 能夠偵測 ASan 可偵測到的錯誤:
- 堆疊和堆積緩衝區溢位或反向溢位
- 釋放後的堆積使用情況
- 超出範圍的堆疊使用情況
- 重複釋放或錯誤釋放
此外,HWASan 也能偵測:
- 傳回後堆疊的使用情況
範例應用程式
建構
如要使用 HWAddress Sanitizer 建構應用程式的原生 (JNI) 程式碼,請執行以下操作:
ndk-build
在 Application.mk
檔案中:
APP_STL := c++_shared # Or system, or none, but not c++_static.
APP_CFLAGS := -fsanitize=hwaddress -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=hwaddress
CMake
在模組的 build.gradle
檔案中:
android {
defaultConfig {
externalNativeBuild {
cmake {
# Can also use system or none as ANDROID_STL, but not c++_static.
arguments "-DANDROID_STL=c++_shared"
}
}
}
}
針對 CMakeLists.txt 中的每個目標:
target_compile_options(${TARGET} PUBLIC -fsanitize=hwaddress -fno-omit-frame-pointer)
target_link_options(${TARGET} PUBLIC -fsanitize=hwaddress)
使用 NDK 27 以上版本時,您也可以在 build.gradle
中使用下列指令,而不需要變更 CMakeLists.txt:
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DANDROID_SANITIZE=hwaddress"
}
}
}
}
使用 ANDROID_USE_LEGACY_TOOLCHAIN_FILE=false
時,這項功能將無法運作。
Android 14 以上版本:新增 wrap.sh
如果執行的是 Android 14 以上版本,可以在任何 Android 裝置上使用 wrap.sh 指令碼執行可偵錯應用程式。如果選擇按照「設定操作說明」中的步驟進行,請略過這個步驟。
按照操作說明封裝 wrap.sh 指令碼,為 arm64-v8a
新增下列 wrap.sh 指令碼。
#!/system/bin/sh
LD_HWASAN=1 exec "$@"
執行
如果您執行的 Android 版本低於 14,或是未新增 wrap.sh 指令碼,請先按照設定操作說明執行應用程式。
照常執行應用程式。系統偵測到記憶體錯誤時,應用程式會因 SIGABRT 而異常終止,並在 Logcat 中顯示詳細訊息。您可以在 /data/tombstones
底下的檔案中找到這則訊息,內容如下:
ERROR: HWAddressSanitizer: tag-mismatch on address 0x0042a0826510 at pc 0x007b24d90a0c
WRITE of size 1 at 0x0042a0826510 tags: 32/3d (ptr/mem) in thread T0
#0 0x7b24d90a08 (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x2a08)
#1 0x7b8f1e4ccc (/apex/com.android.art/lib64/libart.so+0x198ccc)
#2 0x7b8f1db364 (/apex/com.android.art/lib64/libart.so+0x18f364)
#3 0x7b8f2ad8d4 (/apex/com.android.art/lib64/libart.so+0x2618d4)
0x0042a0826510 is located 0 bytes to the right of 16-byte region [0x0042a0826500,0x0042a0826510)
allocated here:
#0 0x7b92a322bc (/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so+0x212bc)
#1 0x7b24d909e0 (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x29e0)
#2 0x7b8f1e4ccc (/apex/com.android.art/lib64/libart.so+0x198ccc)
訊息後面可能會附加額外的偵錯資訊,包括應用程式正在使用的執行緒清單、鄰近記憶體配置的標記和 CPU 註冊值。
如要進一步瞭解 HWASan 錯誤訊息,請參閱「瞭解 HWASan 報告」一文。
建構指令列可執行檔
您可以在 Android 14 以上版本上建構及執行以 HWASan 檢測的執行檔。您可以使用與「建構」一節所述相同的設定,為可執行檔使用 ndk-build 或 CMake。將可執行檔推送至搭載 Android 14 以上版本的裝置,並使用 Shell 正常執行。
如果您使用的是 libc++,請務必使用共用 STL,並將其推送至裝置,並在執行二進位檔時,將 LD_LIBRARY_PATH
設為包含 STL 的目錄。
如果您未使用 Gradle,請參閱 NDK 說明文件,瞭解如何透過指令列使用 CMake 和 ndk-build 進行建構。
Android 13 以下版本:設定
如果裝置搭載的是 Android 14 以上版本,可以略過這個步驟,並按照下方「建構」一節中使用 wrap.sh 的操作說明進行。您也可以選擇按照本節所述操作,略過使用 wrap.sh 的操作說明。
在 Android 14 之前,HWASan 應用程式需要 Android HWASan 版本,才能順利執行。 您可以將預先建構的 HWASan 映像檔刷新至支援的 Pixel 裝置。您可在 ci.android.com 中找到這些版本,只要按一下所需確切版本的正方形,就能取得刷新版本連結。為此,您需要知道手機的產品代號。
更簡單的做法是直接造訪 flash.android.com,因為在這個作業流程中,系統會從偵測裝置開始,並僅列出您可以使用的建構內容。下圖說明這項工具的設定流程。
在裝置上啟用開發人員模式,然後透過 USB 傳輸線將裝置連接至電腦。按一下「Add new device」,從對話方塊中選取您的裝置,然後按一下「Connect」。
連接裝置後,按一下該裝置即可設定版本。
在「Select a build ID」方塊中,選取 aosp-master-with-phones-throttled
分支版本,讓系統自動為已連接的裝置選擇正確的映像檔。
按一下「Install」刷新裝置。
如要進一步瞭解必要的設定,請參閱 Android Flash Tool 說明文件。另外,您也可以參閱 Android 開放原始碼計畫說明文件,瞭解如何從來源建構 HWASan 映像檔。