HWASan 工具偵測到記憶體錯誤時,會以 abort()
終止程序,並將報告輸出至 stderr 和 Logcat。與 Android 上的所有原生當機情形一樣,HWASan 錯誤會顯示在 /data/tombstones
下方。
範例報表
與一般原生異常終止情形相比,HWASan 會在位於墓碑頂端附近的「Abort message」欄位中提供額外資訊。以下是堆積式異常終止的範例。如要瞭解堆疊錯誤,請參閱堆疊專屬章節的附註。
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** Build fingerprint: 'google/flame_hwasan/flame:Tiramisu/MASTER/7956676:userdebug/dev-keys' Revision: 'DVT1.0' ABI: 'arm64' Timestamp: 2019-04-24 01:13:22+0000 pid: 11154, tid: 11154, name: sensors@1.0-ser >>> /vendor/bin/hw/android.hardware.sensors@1.0-service <<< signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr -------- Abort message: '==9569==ERROR: HWAddressSanitizer: tag-mismatch on address 0x00433ae20045 at pc 0x00623ae2a9cc READ of size 1 at 0x00433ae20045 tags: 5b/83 (ptr/mem) in thread T0 #0 0x7240450c68 (/system/lib64/vndk-sp-R/libcutils.so+0x8c68) #1 0x723dffd490 (/vendor/lib64/sensors.ssc.so+0x34490) #2 0x723e0126e0 (/vendor/lib64/sensors.ssc.so+0x496e0) [...] [0x00433ae20040,0x00433ae20060) is a small unallocated heap chunk; size: 32 offset: 5 Cause: use-after-free 0x00433ae20045 is located 5 bytes inside of 10-byte region [0x00433ae20040,0x00433ae2004a) freed by thread T0 here: #0 0x72404d1b18 (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0x10b18) #1 0x723af23040 (/vendor/lib64/libgralloccore.so+0x5040) #2 0x723af23fa4 (/vendor/lib64/libgralloccore.so+0x5fa4) [...] previously allocated here: #0 0x72404ce554 (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0xd554) #1 0x7240115654 (/apex/com.android.runtime/lib64/bionic/libc.so+0x43654) #2 0x7240450ac8 (/system/lib64/vndk-sp-R/libcutils.so+0x8ac8) [...] hwasan_dev_note_heap_rb_distance: 1 1023 hwasan_dev_note_num_matching_addrs: 0 hwasan_dev_note_num_matching_addrs_4b: 0 Thread: T0 0x006a00002000 stack: [0x007fc1064000,0x007fc1864000) sz: 8388608 tls: [0x00737702ffc0,0x007377033000) Memory tags around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1f90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x006f33ae2000: 08 00 08 00 [83] 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Tags for short granules around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1ff0: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. =>0x006f33ae2000: 72 .. d0 .. [..] .. .. .. .. .. .. .. .. .. .. .. 0x006f33ae2010: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags Registers where the failure occurred (pc 0x00623ae2a9cc): x0 0000007fc18623ec x1 5b0000433ae20045 x2 0000000000000013 x3 ffffffffffffffff x4 ffffffffffffffff x5 0000007fc1861da3 x6 6f7420676e696f47 x7 45522061206f6420 x8 0000000000000000 x9 0200006b00000000 x10 00000007fc18623f x11 5b0000433ae20040 x12 6f64206f7420676e x13 0a44414552206120 x14 0000000000000010 x15 ffffffffffffffff x16 000000737169ac94 x17 0000000000000007 x18 0000007377bd8000 x19 0000007fc1862498 x20 0200006b00000000 x21 0000007fc18624a8 x22 0000000000000001 x23 0000000000000000 x24 0000000000000000 x25 0000000000000000 x26 0000000000000000 x27 0000000000000000 x28 0000000000000000 x29 0000007fc1862410 x30 000000623ae2a9d0 sp 0000007fc18623d0 SUMMARY: HWAddressSanitizer: tag-mismatch (/system/lib64/vndk-sp-R/libcutils.so+0x8c68) [ … regular crash dump follows …]
這與 AddressSanitizer 報告類似。與上述情況不同,幾乎所有 HWASan 錯誤都是標記不相符的錯誤,也就是指標標記與對應的記憶體標記不相符的記憶體存取情形。這可以是下列任一項目:
- 在堆疊或堆積上超出邊界存取
- 堆積上的釋放後使用錯誤
- 堆疊上的回傳後使用錯誤
區段
以下說明 HWASan 報表的各個部分。
存取錯誤
包含不正確記憶體存取的相關資訊,包括:
- 存取類型 (
READ
與WRITE
) - 存取大小 (嘗試存取的位元組數量)
- 存取的執行緒編號
- 指標和記憶體標記 (用於進階偵錯)
存取堆疊追蹤記錄
錯誤記憶體存取的堆疊追蹤。請參閱「符號化」一文,瞭解如何符號化。
原因
導致存取權異常的可能原因。如果有多個候選項,系統會依可能性高低列出。此欄位會先顯示潛在原因的詳細資訊。HWASan 可診斷以下原因:
- 釋放後使用
- 堆疊標記不相符,可能為回傳後使用堆疊、範圍後使用堆疊或超出邊界
- 堆積緩衝區溢位
- 全域溢位
記憶體資訊
說明 HWASan 對存取記憶體的瞭解程度,這可能因錯誤類型而異:
錯誤類型 | 原因 | 報表格式 |
---|---|---|
標記不符 | 釋放後使用 | 請使用以下報表格式:<address> is located N bytes inside of M-byte region [<start>, <end>) freed by thread T0 here: |
堆積緩衝區溢位 | 請注意,這也可能是負溢。<address> is located N bytes to the right of M-byte region [<start>, <end>) allocated here: |
|
堆疊標記不符 | 堆疊報表不會區分溢位或反向溢位和使用後回傳錯誤。此外,如要找出錯誤來源的堆疊配置,您必須執行離線符號化步驟。請參閱「瞭解堆疊報表」。 | |
無效的免費 | 釋放後使用 | 重複釋放錯誤。如果在程序關閉時發生這種情況,可能表示發生ODR 違規。<address> is located N bytes inside of M-byte region [<start>, <end>) freed by thread T0 here: |
無法描述地址 | 要不是隨機釋放 (釋出先前未分配的記憶體),就是在已分配的記憶體從 HWASan 的 free 緩衝區中淘汰後,釋放兩次。 | |
0x... 是 HWAsan 陰影記憶體 | 應用程式嘗試釋放 HWASan 內部的記憶體,因此發生記憶體釋放異常。 |
解除配置堆疊追蹤
記憶體釋放位置的堆疊追蹤。僅針對使用釋放後記憶體或無效記憶體錯誤顯示。請參閱「符號化」一文,瞭解如何進行符號化。
配置堆疊追蹤
記憶體分配位置的堆疊追蹤。請參閱「符號化」一文,瞭解如何進行符號化。
進階偵錯資訊
HWASan 報表也提供一些進階偵錯資訊,包括 (依序):
- 程序中的執行緒清單
- 程序中的執行緒清單
- 發生錯誤記憶體附近的記憶體標記值
- 在記憶體存取點時傾印暫存器
記憶體標記傾印
您可以使用標記記憶體傾印,尋找與指標標記相同標記的附近記憶體配置。這些標記可指出偏移量較大的越界存取行為。一個標記對應 16 位元的記憶體;指標標記是位址的前 8 位元。標記記憶體傾印可提供提示,例如,以下是右側的緩衝區溢位:
tags: ad/5c (ptr/mem) [...] Memory tags around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1ff0: 0e 0e 0e 57 20 20 20 20 20 2e 5e 5e 5e 5e 5e b5 =>0x006f33ae2000: f6 f6 f6 f6 f6 4c ad ad ad ad ad ad [5c] 5c 5c 5c 0x006f33ae2010: 5c 04 2e 2e 2e 2e 2e 2f 66 66 66 66 66 80 6a 6a Tags for short granules around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1ff0: ab 52 eb .. .. .. .. .. .. .. .. .. .. .. .. .. =>0x006f33ae2000: .. .. .. .. .. .. .. .. .. .. .. .. [..] .. .. .. 0x006f33ae2010: .. 5c .. .. .. .. .. .. .. .. .. .. .. .. .. ..
請注意,左側的 ad
標記有 6 × 16 = 96 個位元組,與指標標記相符。
如果配置的大小不是 16 的倍數,大小的餘數會儲存為 記憶體標記,而標記會儲存為 短精細標記。在前述範例中,在標記為 ad
的粗體分配值之後,我們有 5 × 16 + 4 = 84 個位元組的標記 5c
分配值。
零記憶體標記 (例如 tags: ad/00 (ptr/mem)
) 表示「使用已釋放的堆疊」錯誤。
註冊傾印
HWASan 報告中的登錄檔轉儲作業會對應至執行無效記憶體存取作業的指令。此傾印作業之後,會由一般 Android 信號處理常式程式執行另一個註冊傾印作業。忽略第二個傾印,因為該傾印是在 HWASan 呼叫 abort()
時擷取,與錯誤無關。
符號化
如要取得堆疊追蹤中的函式名稱和行號 (以及取得用於作用範圍後使用錯誤的變數名稱),就必須進行離線符號化步驟。
首次設定:安裝 llvm-symbolizer
如要進行符號化,系統必須安裝 llvm-symbolizer
,並可從 $PATH
存取。在 Debian 上,您可以使用 sudo apt install llvm
安裝。
取得符號檔案
符號化功能需要未經去除的二進位檔,其中包含符號。位置取決於版本類型:
- 對於本機版本,符號檔案位於
out/target/product/<product>/symbols/
中。 - 對於 AOSP 版本 (例如透過 Android Flash Tool 刷新),這些版本會在 Android CI 上執行。在建構的「構件」中,有一個
${PRODUCT}-symbols-${BUILDID}.zip
檔案。 - 如果是貴機構的內部版本,請參閱貴機構的文件,瞭解如何取得符號檔案。
符號化
hwasan_symbolize --symbols <DECOMPRESSED_DIR>/out/target/product/*/symbols < crash
瞭解堆疊報表
如果是堆疊變數發生的錯誤,HWASan 報告會包含以下詳細資料:
Cause: stack tag-mismatch Address 0x007d4d251e80 is located in stack of thread T64 Thread: T64 0x0074000b2000 stack: [0x007d4d14c000,0x007d4d255cb0) sz: 1088688 tls: [0x007d4d255fc0,0x007d4d259000) Previously allocated frames: record_addr:0x7df7300c98 record:0x51ef007df3f70fb0 (/apex/com.android.art/lib64/libart.so+0x570fb0) record_addr:0x7df7300c90 record:0x5200007df3cdab74 (/apex/com.android.art/lib64/libart.so+0x2dab74) [...]
為協助您瞭解堆疊錯誤,HWASan 會追蹤過去的堆疊框架。HWASan 不會將這些內容轉換為錯誤報告中人類可理解的內容,因此需要額外的符號化步驟。
ODR 違規
HWASan 回報的部分使用後釋放錯誤,可能表示違反「單一定義規則」(ODR)。如果同一個程式中定義了相同的變數多次,就會發生 ODR 違規。這也表示變數會多次解構,可能會導致使用後釋放錯誤。
符號化後,ODR 違規事項會在無效存取堆疊和 freed here 堆疊上,顯示 __cxa_finalize
的使用後釋放錯誤。先前在此處分配的堆疊包含 __dl__ZN6soinfo17call_constructorsEv
,且應指向程式中定義堆疊上方變數的位置。
如果使用靜態程式庫,可能會違反 ODR。如果定義 C++ 全域的靜態程式庫連結至多個共用程式庫或可執行檔,同一個位址空間可能會存在多個相同符號的定義,進而導致 ODR 錯誤。
疑難排解
本節將說明一些錯誤及其解決方法。
HWAddressSanitizer 無法進一步說明地址
有時 HWASan 可能會用盡空間,無法儲存過去記憶體配置的資訊。在這種情況下,報告只會包含一個立即記憶體存取的堆疊追蹤,並附上以下註解:
HWAddressSanitizer can not describe address in more detail.
在某些情況下,您可以多次執行測試來解決這個問題。另一個選項是增加 HWASan 記錄大小。您可以在 build/soong/cc/sanitize.go
中全域執行這項操作 (請查看 hwasanGlobalOptions
),或在程序環境中執行 (請嘗試 adb shell echo $HWASAN_OPTIONS
查看目前的設定)。
如果未對存取的記憶體進行對應,或由非 HWASan 感知的配置器配置記憶體,也可能發生此錯誤。在這種情況下,當機標頭中列出的 mem
標記通常是 00
。如果您可以存取完整的墓碑,建議您查看記憶體對應資料轉儲,找出地址屬於哪個對應 (如果有的話)。
同一個執行緒中的巢狀錯誤
這表示產生 HWASan 當機報告時發生錯誤。這通常是因為 HWASan 執行階段中的錯誤。回報錯誤,並提供重現問題的操作說明 (如有)。