HWASan ツールがメモリのバグを検出すると、プロセスが abort() で終了し、stderr と logcat にレポートが出力されます。HWASan エラーは、Android のネイティブ コードでのクラッシュと同じ /data/tombstones
に格納されます。
HWASan の追加情報は、通常のネイティブ コードでのクラッシュとは異なり、tombstone の上部にある「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 レポートの各セクションについて説明します。
アクセス エラー
不正なメモリアクセスに関する情報が含まれています。たとえば、以下に関する不正がレポートされます。
- アクセスタイプ(「読み取り」と「書き込み」)
- アクセスサイズ(アクセスが試行されたバイト数)
- アクセスのスレッド数
- ポインタとメモリタグ(高度なデバッグ用)
アクセスのスタック トレース
不正なメモリアクセスのスタック トレースです。シンボル化については、シンボル化のセクションをご覧ください。
原因
不正なアクセスの原因として考えられる候補です。候補が複数ある場合は、可能性が高い順に一覧表示されます。その後に、考えられる原因についての詳細情報が記載されます。HWASan では以下の原因を診断できます。
- use-after-free(解放後の使用)
- スタックの tag-mismatch(タグの不一致): スタックの use-after-return(返却後の使用)、use-after-scope(領域外の使用)、または境界外のアクセス
- heap-buffer-overflow(ヒープのバッファ オーバーフロー)
- global-overflow(グローバル オーバーフロー)
メモリ情報
アクセス対象のメモリについて HWASan が認識している情報です。バグの種類によって内容が異なる場合があります。
バグの種類 | 原因 | レポート形式 |
---|---|---|
tag-mismatch | use-after-free(解放後の使用) |
<address> is located N bytes inside of M-byte region [<start>, <end>) freed by thread T0 here: |
heap-buffer-overflow(ヒープのバッファ オーバーフロー) | アンダーフローの場合もあります。<address> is located N bytes to the right of M-byte region [<start>, <end>) allocated here: |
|
スタックの tag-mismatch | スタック レポートでは、オーバーフロー / アンダーフローと use-after-return バグは区別されません。また、エラーの原因となったスタック割り当てを特定するには、オフラインでのシンボル化ステップが必要になります。下記のスタック レポートについてのセクションを参照してください。 | |
invalid-free(無効な解放) | use-after-free(解放後の使用) | 二重解放バグです。<address> is located N bytes inside of M-byte region [<start>, <end>) freed by thread T0 here: |
アドレスを記述できない | ワイルド解放(事前に割り当てられていなかったメモリの解放)、または割り当てられたメモリが HWASan の空きバッファから強制排除された後の二重解放です。 | |
0x… が HWAsan シャドウメモリ。 | アプリが HWASan の内部のメモリを解放しようとしていました。これは明らかにワイルド解放です。 |
割り当て解除のスタック トレース
メモリが割り当て解除された場合のスタック トレースです。use-after-free バグまたは invalid-free バグの場合にのみ表示されます。シンボル化については、シンボル化を参照してください。
割り当てのスタック トレース
メモリが割り当てられた場合のスタック トレースです。シンボル化については、シンボル化を参照してください。
高度なデバッグ情報
HWASan レポートには、以下のような高度なデバッグ情報も含まれています。
- プロセス内のスレッドのリスト
- プロセス内のスレッドのリスト
- 障害が発生したメモリ付近のメモリタグの値
- メモリアクセス ポイントでのレジスタのダンプ
メモリタグ ダンプ
タグメモリ ダンプを使用すると、ポインタタグと同じタグに隣接するメモリの割り当てを探すことができます。オフセットが大きく、境界外のアクセスを指している場合もあります。1 つのタグは 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 .. .. .. .. .. .. .. .. .. .. .. .. .. ..
割り当てのサイズが 16 の倍数でない場合は、サイズの残りがメモリタグとして保存され、タグは短いグラニュール タグとして保存されます。上の例では、ad とタグ付けされた太字の割り当ての直後に、5 × 16 + 4 = 84 バイトのタグ 5c が割り当てられています。
ゼロメモリタグ(例: tags: ad/00 (ptr/mem)
)は、通常はスタック使用後のバグを示します。
レジスタダンプ
HWASan レポートのレジスタダンプは、不正なメモリアクセスが行われた実際の命令に対応しています。その後に、通常の Android シグナル ハンドラから別のレジスタダンプが続きます。2 番目のレジスタダンプは無視してください。これは HWASan が abort() を呼び出したときに記録されたもので、バグとは無関係です。
シンボル化
スタック トレース内の関数名と行番号(および use-after-scope バグの変数名)を取得するには、オフラインでのシンボル化ステップが必要になります。
初期設定: llvm-symbolizer をインストールする
シンボル化するには、システムに llvm-symbolizer をインストールし、$PATH からアクセスできるようにする必要があります。Debian では、sudo apt install llvm
を使用してインストールできます。
シンボル ファイルを取得する
シンボル化には、シンボルが格納されたストリップされていないバイナリが必要です。このシンボル ファイルの場所は、ビルドの種類によって異なります。
ローカルビルドの場合、シンボル ファイルは out/target/product/<product>/symbols/
にあります。
AOSP ビルドの場合(たとえば Flashstation からフラッシュする場合)、ビルドは Android CI にあります。ビルドの「Artifacts」に、「${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 では、過去に発生したスタック フレームを記録して、スタックのバグについて理解できるようにしています。ただし、現時点のバグレポートでは人間が理解できる形式には変換されておらず、追加のシンボル化ステップが必要になります。
トラブルシューティング
"HWAddressSanitizer can not describe address in more detail."(HWAddressSanitizer はアドレスをこれ以上詳しく記述できません。)
HWASan では、過去のメモリ割り当てに関する情報を格納する領域が不足することがあります。その場合、レポートには直近のメモリアクセスのスタック トレースが 1 つだけ含まれ、その後に次の注記が追加されます。
HWAddressSanitizer can not describe address in more detail.
場合によっては、テストを複数回実行することでこの問題を解決できます。別の方法として、HWASan の履歴サイズを増やすこともできます。この設定は、build/soong/cc/sanitize.go
の hwasanGlobalOptions
でグローバルに変更することもできますし、プロセス環境で変更することもできます(現在の設定は adb shell echo $HWASAN_OPTIONS
で確認できます)。
"nested bug in the same thread"(同じスレッドにネストされたバグがあります)
これは、HWASan クラッシュ レポートの生成時にバグがあったことを意味します。通常は HWASan ランタイムのバグによるものです。バグを報告し、可能であれば問題を再現する方法をお知らせください。