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-coverage=edge
) - インライン 8 ビット カウンター (
/fsanitize-coverage=inline-8bit-counters
) - 比較 (
/fsanitize-coverage=trace-cmp
) - 整数除算 (
/fsanitize-coverage=trace-div
)
/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
を定義して LLVMFuzzerInitialize
と LLVMFuzzerTestOneInput
を呼び出す必要があります。 これらのライブラリのいずれかを使用するには、 /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 を使用してキャッチするには、次のことをしなければなりません。
/fsanitize-address-use-after-return
オプションを使用してコンパイルします。- プログラムを実行する前に、
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 規則は、通常、i386
やx86_64
ではなく、x86
およびx64
されます。 これらは、同じアーキテクチャを参照します。
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 for all Runtime Configurationsを参照してください。
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 エラーの例