HWAddressSanitizer

Android NDK は、NDK r21 および Android 10(API レベル 29)以降で HWAddressSanitizer(HWASan)をサポートしています。HWASan は 64 ビットの Arm デバイスでのみ使用できます。

HWASan は ASan と似たメモリエラー検出ツールです。従来の ASan と比較した HWASan の特徴を次に示します。

  • CPU オーバーヘッドは同程度(~2 倍)
  • コードサイズ オーバーヘッドは同程度(40~50%)
  • RAM オーバーヘッドは大幅に少ない(10~35%)

HWASan は ASan と同じ種類のバグを検出します。

  • スタックとヒープのバッファ オーバーフローまたはアンダーフロー
  • 解放後のヒープ使用
  • スコープ外のスタック使用
  • 二重解放またはワイルド解放

さらに、HWASan は以下も検出します。

  • 返却後のスタック使用

サンプルアプリ

サンプルアプリは、HWASan 用にビルド バリアントを構成する方法を示しています。

ビルド

HWAddressSanitizer を使用してアプリのネイティブ(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 以降を実行している場合は、wrap.sh スクリプトを使用して任意の Android 搭載デバイスでデバッグ可能アプリを実行できます。セットアップ手順の手順に沿って操作する場合は、この手順をスキップできます。

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 以降を搭載したデバイスに push し、シェルを使用して通常どおり実行します。

libc++ を使用している場合は、共有 STL を使用していることを確認し、デバイスに push して、バイナリを実行するときに LD_LIBRARY_PATH をそのディレクトリに設定します。

Gradle を使用していない場合は、NDK のドキュメントで、CMakendk-build を使用してコマンドラインからビルドする方法をご覧ください。

Android 13 以前: セットアップ

Android 14 以降を搭載したデバイスの場合は、この手順をスキップして、ビルド セクションの wrap.sh を使用する手順に沿って操作してください。また、このセクションの手順をスキップせず、wrap.sh を使用する手順をスキップすることもできます。

Android 14 より前のバージョンの場合、HWASan アプリを実行するには Android の HWASan ビルドが必要です。サポートされている Pixel デバイスに、事前ビルド済みの HWASan イメージをフラッシュできます。ビルドは ci.android.com で入手できます。ここで必要なビルドの正方形をクリックすると、[Flash Build] リンクが表示されます。そのためには、使用しているスマートフォンのコードネームを知る必要があります。

デバイスのビルドをフラッシュする

このフローは、最初にデバイスを検出した後、使用可能なビルドのみを表示します。したがって、flash.android.com に直接アクセスするほうが簡単な場合があります。以下の画像は、このツールの設定フローを示しています。

デバイスでデベロッパー モードを有効にし、USB ケーブルを使用してデバイスをパソコンに接続します。[Add new device] をクリックし、ダイアログからデバイスを選択して、[Connect] をクリックします。

フラッシュするデバイスを検出する 接続するデバイスを選択する

デバイスが接続されたら、デバイスをクリックしてビルドを構成します。[Select a build ID] ボックスで aosp-master-with-phones-throttled ブランチを選択すると、接続したデバイス用の正しいイメージが自動的に選択されます。

フラッシュするデバイスを選択する フラッシュ オプションを確認してデバイスをフラッシュする

[Install] をクリックしてデバイスをフラッシュします。

必要な設定の詳細については、Android Flash Tool のドキュメントをご覧ください。または、ソースから HWASan イメージをビルドすることもできます。その手順については、AOSP のドキュメントで確認してください。