Share via


AddressSanitizer 言語、ビルド、およびデバッグのリファレンス

この記事のセクションでは、AddressSanitizer の言語仕様、コンパイラ オプション、リンカー オプションについて説明します。 また、AddressSanitizer に固有の Visual Studio デバッガー統合を制御するオプションについても説明します。

AddressSanitizer ランタイムの詳細については、「ランタイムのリファレンス」を参照してください。 インターセプトされた関数に関する情報と、カスタム アロケーターをフックする方法についても説明します。 AddressSanitizer の障害のクラッシュ ダンプの保存に関する詳細は、「クラッシュ ダンプのリファレンス」を参照してください。

言語仕様

__SANITIZE_ADDRESS__

__SANITIZE_ADDRESS__ プリプロセッサ マクロは /fsanitize=address が設定されているとき 1 として定義されています。 このマクロは、上級ユーザーが AddressSanitizer ランタイムの存在についてソース コードを条件付きで指定する場合に便利です。

#include <cstdio>

int main() {
    #ifdef __SANITIZE_ADDRESS__
        printf("Address sanitizer enabled");
    #else
        printf("Address sanitizer not enabled");
    #endif
    return 1;
}

__declspec(no_sanitize_address)

__declspec(no_sanitize_address) 指定子を使用して、サニタイザーを関数、ローカル変数、またはグローバル変数で選択的に無効にすることができます。 この __declspec は、ランタイムの動作でなく、コンパイラの動作に影響を与えます。

__declspec(no_sanitize_address)
void test1() {
    int x[100];
    x[100] = 5; // ASan exception not caught
}

void test2() {
    __declspec(no_sanitize_address) int x[100];
    x[100] = 5; // ASan exception not caught
}

__declspec(no_sanitize_address) int g[100];
void test3() {
    g[100] = 5; // ASan exception not caught
}

コンパイラ

/fsanitize=address コンパイラ オプション

/fsanitize=address コンパイラ オプションは、コード内のメモリ参照をインストルメント化して、実行時のメモリ安全性エラーをキャッチします。 インストルメンテーションは、読み込み、ストア、スコープ、alloca、および CRT の各関数をフックします。 out-of-bounds、use-after-free、use-after-scope などの隠れたバグを検出することができます。 実行時に検出されたエラーの存在しない一覧については、AddressSanitizer エラーの例を参照してください

/fsanitize=address は既存のすべての C++ または C 最適化レベル (たとえば /Od/O1/O2/O2 /GL、およびプロファイルに基づく最適化) と互換性があります。 このオプションを使用して生成されたコードは、静的および動的 CRT (/MD/MDd/MT/MTd など) と連動します。 このコンパイラ オプションを使用して、x86 または x64 を対象とする .EXE または .DLL を作成できます。 最良の呼び出し履歴の書式設定をするためにデバッグ情報が必要です。

さまざまな種類のエラー検出を示すコード例については、「AddressSanitizer error のエラー例」を参照してください。

/fsanitize=fuzzer コンパイラオプション (試験段階)

/fsanitize=fuzzer コンパイラ オプションは LibFuzzer を既定のライブラリ リストに追加します。 また、次のサニタイザー カバレッジ オプションも設定します。

/fsanitize=address/fsanitize=fuzzer と使用することをお勧めします。

/fsanitize=fuzzer を指定すると、以下のライブラリが既定のライブラリ一覧に追加されます。

ランタイム オプション LibFuzzer ライブラリ
/MT clang_rt.fuzzer_MT-{arch}
/MD clang_rt.fuzzer_MD-{arch}
/MTd clang_rt.fuzzer_MTd-{arch}
/MDd clang_rt.fuzzer_MDd-{arch}

main 関数を省略する LibFuzzer ライブラリも使用できます。 これらのライブラリを使用するときは、main を定義して LLVMFuzzerInitializeLLVMFuzzerTestOneInput を呼び出す必要があります。 これらのライブラリのいずれかを使用するには、ランタイムとアーキテクチャに対応する次のライブラリを指定 /NODEFAULTLIB して明示的にリンクします。

ランタイム オプション LibFuzzer no_main ライブラリ
/MT clang_rt.fuzzer_no_main_MT-{arch}
/MD clang_rt.fuzzer_no_main_MD-{arch}
/MTd clang_rt.fuzzer_no_main_MTd-{arch}
/MDd clang_rt.fuzzer_no_main_MDd-{arch}

/NODEFAULTLIB を指定し、これらのライブラリのいずれかを指定しない場合は、未解決の外部シンボル リンク エラーが表示されます。

/fsanitize-address-use-after-return コンパイラオプション (試験段階)

既定では、MSVC コンパイラは (Clang とは違って)、ヒープ内のフレームを割り当てて use-after-return エラーをキャッチするコードを生成しません。 これらのエラーを AddressSanitizer を使用してキャッチするには、次のことをしなければなりません。

  1. /fsanitize-address-use-after-return オプションを使用してコンパイルします。
  2. プログラムを実行する前に、set ASAN_OPTIONS=detect_stack_use_after_return=1 を実行 してランタイム チェック オプションを設定します。

この/fsanitize-address-use-after-returnオプションを指定すると、ローカルが "アドレス取得" と見なされたときに、ヒープ内でデュアル スタック フレームを使用するコードがコンパイラによって生成されます。このコードは、単独で使用/fsanitize=addressするよりもはるかに低速です。 詳細と例については、「エラー: stack-use-after-return」を参照してください。

ヒープ内のデュアル スタック フレームは、それを作成した関数からの戻りの後に残っています。 ヒープ内のスロットに割り当てられた、ローカルのアドレスが、戻りの後のどこで使用されるかの例を考えてみましょう。 フェイク ヒープ フレームに関連付けられているシャドウバイトには、値 0xF9 が含まれます。 その 0xF9 は、ランタイムがエラーを報告したときの stack-use-after-return エラーを意味します。

スタック フレームがヒープ内に割り当てられて、関数戻りの後も残ります。 ランタイムはガベージ コレクションを使用して、これらのフェイク call-frame オブジェクトを、特定の間隔の後に、非同期的に解放します。 ローカルのアドレスがヒープ内の永続フレームに転送されます。 このようにして、定義関数の戻りの後で任意のローカルがいつ使用されるかをシステムは検出できます。 詳細については、Google のドキュメントに記載されている「戻り後のスタック使用のアルゴリズム」に関する説明を参照してください。

リンカー

/INFERASANLIBS[:NO] リンカー オプション

コンパイラ オプションは /fsanitize=address 、実行可能ファイルにリンクする AddressSanitizer ライブラリを指定するオブジェクトをマークします。 ライブラリには、clang_rt.asan* で始まる名前が付いています。 /INFERASANLIBS リンカー オプション (既定では on) は、これらのライブラリを既定の場所から自動的にリンクします。 選択され、自動的にリンクされるライブラリを次に示します。

Note

次の表では、 {arch} どちらか i386 です x86_64。 これらのライブラリは、アーキテクチャ名に Clang 規則を使用します。 MSVC の規則は、通常x86x64および .i386x86_64 これらは、同じアーキテクチャを参照します。

CRT オプション AddressSanitizer ランタイム ライブラリ (.lib) ランタイム バイナリのアドレス指定 (.dll)
/MT または /MTd clang_rt.asan_dynamic-{arch}, clang_rt.asan_static_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MD または /MDd clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}

リンカー オプション /INFERASANLIBS:NO を指定すると、リンカーは clang_rt.asan* ライブラリ ファイルを既定の場所からリンクできなくなります。 このオプションを使用する場合は、ライブラリ パスをビルド スクリプトに追加します。 それ以外の場合、リンカーは未解決の外部シンボル エラーを報告します。

以前のバージョン

Visual Studio 17.7 Preview 3 より前では、静的にリンクされた (/MT または /MTd) ビルドでは DLL 依存関係が使用されませんでした。 代わりに、AddressSanitizer ランタイムはユーザーの EXE に静的にリンクされていました。 その後、DLL プロジェクトはユーザーの EXE からエクスポートを読み込んで、ASan 機能にアクセスします。 また、動的にリンクされたプロジェクト (/MD または /MTd) では、プロジェクトがデバッグまたはリリース用に構成されているかどうかに応じて、異なるライブラリと DLL が使用されていました。 これらの変更とその動機の詳細については、「MSVC Address Sanitizer – すべてのランタイム構成に対して 1 つの DLL」を参照してください

CRT ランタイム オプション DLL または EXE AddressSanitizer ランタイムのライブラリ
/MT EXE clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch}
/MT [DLL] clang_rt.asan_dll_thunk-{arch}
/MD 接続前/接続後 clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch}
/MTd EXE clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch}
/MTd [DLL] clang_rt.asan_dbg_dll_thunk-{arch}
/MDd 接続前/接続後 clang_rt.asan_dbg_dynamic-{arch}, clang_rt.asan_dbg_dynamic_runtime_thunk-{arch}

Visual Studio の統合

/fno-sanitize-address-vcasan-lib コンパイラ オプション

/fsanitize=address オプションは、AddressSanitizer 例外がスローされたときの Visual Studio デバッグ エクスペリエンスを向上させるための追加ライブラリのリンクとなります。 これらのライブラリは VCAsan と呼ばれます。 このライブラリにより Visual Studio が AddressSanitizer エラーをソース コードで表示できるようになります。 また、AddressSanitizer エラー レポートが作成されたとき、実行可能ファイルはクラッシュ ダンプを生成できるようにもなります。 詳細については、「Visual Studio AddressSanitizer 拡張機能ライブラリ」を参照してください。

選択されるライブラリはコンパイラ オプションによって異なり、自動的にリンクされます。

ランタイム オプション VCAsan バージョン
/MT libvcasan.lib
/MD vcasan.lib
/MTd libvcasand.lib
/MDd vcasand.lib

ただし、(既定のライブラリ名を省略) を使用して /Zl コンパイルする場合は、ライブラリを手動で指定する必要があります。 そうしない場合、未解決の外部シンボル リンク エラーが発生します。 次にいくつか典型的な例を挙げます:

error LNK2001: unresolved external symbol __you_must_link_with_VCAsan_lib
error LNK2001: unresolved external symbol ___you_must_link_with_VCAsan_lib

向上したデバッグをコンパイル時に無効にするには、/fno-sanitize-address-vcasan-lib オプションを使用します。

ASAN_VCASAN_DEBUGGING 環境変数

/fsanitize=address コンパイラ オプションは、メモリ安全性バグを公開するバイナリを実行時に生成します。 このバイナリがコマンド ラインから開始されて、ランタイムがエラーを報告すると、エラーの詳細が出力されます。 その後に、プロセスを終了します。 ASAN_VCASAN_DEBUGGING 環境変数は、ランタイムがエラーを報告したとき Visual Studio IDE をすぐに起動するように設定できます。 このコンパイラ オプションを設定すると、エラーは、ソース コードに重なり、エラーの原因となった正確な行と列に、表示されます。

この動作を有効にするには、アプリケーションを実行する前にコマンド set ASAN_VCASAN_DEBUGGING=1 を実行します。 強化されたデバッグ エクスペリエンスは、set ASAN_VCASAN_DEBUGGING=0 を実行することで無効にできます。

関連項目

AddressSanitizer の概要
AddressSanitizer の既知の問題
AddressSanitizer ランタイム リファレンス
AddressSanitizer シャドウ バイト
AddressSanitizer クラウドまたは分散テスト
AddressSanitizer デバッガーの統合
AddressSanitizer エラーの例