次の方法で共有


AddressSanitizer

概要

C および C++ 言語は強力ですが、プログラムの正確性とプログラムのセキュリティに影響を与えるバグのクラスに苦しむ可能性があります。 Visual Studio 2019 バージョン 16.9 以降、Microsoft C/C++ コンパイラ (MSVC) と IDE では、 AddressSanitizer サニタイザーがサポートされています。 AddressSanitizer (ASan) は、擬陽性がゼロの数多くの発見しにくいバグを明らかにする、コンパイラおよびランタイム テクノロジです。

AddressSanitizer を使用して、以下にかかる時間を短くします。

  • 基本正確性
  • クロスプラットフォームの移植性
  • セキュリティ
  • ストレス テスト
  • 新しいコードの統合

AddressSanitizer は、もともと Google によって導入、既存のビルド システムと既存のテスト資産を直接使用するランタイム バグ検出テクノロジを提供します。

AddressSanitizer は、Visual Studio プロジェクト システム、CMake ビルド システム、IDE と統合されています。 プロジェクトで AddressSanitizer を有効にするには、プロジェクトのプロパティを設定するか、ひとつの追加コンパイラ オプション /fsanitize=address を使用します。 新しいオプションは、x86 および x64 のすべてのレベルの最適化および構成と互換性があります。 ただし、 edit-and-continueincremental linking、および /RTC と互換性がありません。

Visual Studio 2019 バージョン16.9 以降では、Microsoft の AddressSanitizer テクノロジにより Visual Studio IDE との統合が可能になります。 この機能により、サニタイザーが実行時にバグを発見したとき、必要に応じてクラッシュ ダンプ ファイルを作成できます。 プログラムを実行する前に ASAN_SAVE_DUMPS=MyFileName.dmp 環境変数を設定すると、正確に診断されたバグの 事後分析デバッグ の効率的なメタデータを含むクラッシュ ダンプ ファイルが作成されます。 これらのダンプ ファイルを使用すると、AddressSanitizer を次の目的で簡単に使用できます。

  • ローカル コンピューターのテスト
  • オンプレミスの分散テスト
  • テスト用のクラウドベースのワークフロー

AddressSanitizer のインストール

Visual Studio インストーラーの C++ ワークロードでは、AddressSanitizer ライブラリと IDE 統合が既定でインストールされます。 ただし、以前のバージョンの Visual Studio 2019 からアップグレードする場合は、アップグレード後にインストーラーを使用して ASan サポートを有効にします。 インストーラーは、Tools>Get Tools and Features... を使用して Visual Studio のメイン メニューから開くことができます。Visual Studio インストーラーから既存の Visual Studio インストールで Modify を選択して、次の画面にアクセスします。

Visual Studio インストーラーのスクリーンショット。[省略可能] セクションの下にある C++ AddressSanitizer コンポーネントが強調表示されています。

Note

Visual Studio を新しい更新プログラムで実行しても ASan がインストールされていない場合は、コードを実行すると次のエラーが表示されます。

LNK1356: ライブラリ 'clang_rt.asan_dynamic-i386.lib' が見つかりません

AddressSanitizer を使用する

次の一般的な開発方法のいずれかを使用して、/fsanitize=address コンパイラ オプションを使用した実行可能ファイルのビルドを開始します。

  • コマンドライン ビルド
  • Visual Studio のプロジェクト システム
  • Visual Studio CMake 統合

再コンパイルしてから、プログラムを通常どおり実行します。 このコード生成では、さまざまな種類の正確に診断されたバグが公開されます。 これらのエラーは、デバッガー IDE で、あるいはコマンドラインで報告されるか、あるいは新しい種類のダンプ ファイルに格納されて正確なオフライン処理が行なわれます。

Microsoft では、次の 3 つの標準ワークフローで AddressSanitizer を使用することをお勧めします。

この記事では、前述の 3 つのワークフローを有効にするために必要な情報について説明します。 この情報は、AddressSanitizer プラットフォームに依存 Windows 10 の実装に固有です。 このドキュメントは、既に公開されている Google、Apple、および GCC の優れたドキュメントを補足しています。

Note

現在のサポートが Windows 10 では x86 と x64 に制限されています。 今後のリリースで期待することについて、フィードバックをお送りください。 お送りいただいたフィードバックは、今後の他のサニタイザー (/fsanitize=thread/fsanitize=leak/fsanitize=memory/fsanitize=undefined/fsanitize=hwaddress など) の優先順位を決めるのに役立ちます。 問題が発生した場合は、バグをこちらで報告できます。

開発者コマンド プロンプトから AddressSanitizer を使用する

/fsanitize=address コンパイラ オプションを開発者コマンド プロンプトで使用して、AddressSanitizer ランタイムのコンパイルを有効にします。 /fsanitize=address オプションは、既存のすべての C++ または C 最適化レベル (たとえば /Od/O1/O2/O2 /GLPGO など) と互換性があります。 このオプションは、静的および動的 CRT (たとえば /MD/MDd/MT/MTd など) と連動します。 EXE を作成する場合も DLL を作成する場合も機能します。 最良の呼び出し履歴の書式設定をするためにデバッグ情報が必要です。 次の例では、コマンド ラインで cl /fsanitize=address /Zi が渡されます。

AddressSanitizer ライブラリ (.lib ファイル) は自動的にリンクされます。 詳細については、「AddressSanitizer 言語、ビルド、およびデバッグのリファレンス」をご覧ください。

例 - 基本グローバル バッファー オーバーフロー

// basic-global-overflow.cpp
#include <stdio.h>
int x[100];
int main() {
    printf("Hello!\n");
    x[100] = 5; // Boom!
    return 0;
}

Visual Studio 2019 の開発者コマンド プロンプトを使用して、main.cpp のコンパイルを /fsanitize=address /Zi を使用して行います

AddressSanitizer オプションを使用してコンパイルするコマンドを示すコマンド プロンプトのスクリーンショット。コマンドは 、'cl main.cpp -faanitize-address /Zi' です。

結果の main.exe をコマンド ラインで実行すると、次の書式設定されたエラー レポートが作成されます。

7 つの重要情報を強調表示する、次のような赤色の枠が表示されているとします。

基本的なグローバル オーバーフロー エラーを示すデバッガーのスクリーンショット。

エラー レポートには、重要な情報を識別する 7 つの赤い強調表示があります。 このスクリーンショットに続く番号付きリストにマップされます。 番号付きボックスは、次のテキストを強調表示します。1) グローバル バッファー オーバーフロー 2) サイズ 4 3 の WRITE) basic-global-overflow.cpp 7 4) サイズ 400 6) 00 00[f9]f9 f9 7) ボックスがシャドウ バイト凡例領域にあり、グローバル レッドゾーン f9 で定義されているグローバル変数 basic-global-overflow.cpp 'x' の右側に表示されます。

赤の強調表示 (上から下へ)

  1. メモリ安全性のバグは、グローバルバッファーオーバーフローです。
  2. 4 バイト (32 ビット) がユーザー定義変数の外側に格納されています。
  3. ストアは、ファイル basic-global-overflow.cpp の 7 行目で定義されている main() 関数で行なわれました。
  4. x という名前の変数は 3 行目の basic-global-overflow.cpp で定義されており、列 8 で開始しています。
  5. このグローバル変数 x のサイズは 400 バイトです。
  6. ストアの対象となるアドレスを記述する正確なシャドウ バイトには、0xf9 の値があります。
  7. シャドウバイトの凡例は、0xf9int x[100] の右側のパディングの領域であることを示します。

Note

呼び出し履歴内の関数名は、エラー時にランタイムによって呼び出される LLVM シンボライザーによって生成されます。

Visual Studio で AddressSanitizer を使用する

AddressSanitizer は Visual Studio IDE と統合されています。 MSBuild プロジェクトの AddressSanitizer を有効にするには、ソリューション エクスプローラーでプロジェクトを右クリックし、Properties を選択します。 [プロパティ ページ] ダイアログで、[構成プロパティ]>[C/C++]>[全般] を選択してから、[AddressSanitizer を有効にする] プロパティを変更します。 [OK] を選択して変更を保存します。

[AddressSanitizer の有効化] プロパティを示す [プロパティ ページ] ダイアログのスクリーンショット。

IDE からビルドするには、互換性のないオプションをオプトアウトします。 /Od (またはデバッグ モード) を使用 してコンパイルした既存のプロジェクトの場合は、次のオプションをオフにする必要があります。

デバッガーをビルドして実行するには、 F5 キーを押します。 Visual Studio に Exception Thrown ウィンドウが表示されます。

グローバル バッファー オーバーフロー エラーを示すデバッガーのスクリーンショット。

Visual Studio から AddressSanitizer を使用する: CMake

Windows をターゲットとして作成された CMake プロジェクトに対して AddressSanitizer を有効にするには次の手順に従います。

  1. IDE の上部にあるツール バーの [構成] ドロップダウンを開いて、[構成の管理] を選択します。

    [CMake 構成] ドロップダウンのスクリーンショット。x64 デバッグ、x64 リリースなどのオプションが表示されます。一覧の下部にある [構成の管理]...が強調表示されています。

    CMake プロジェクト設定エディターが開き、プロジェクトの CMakeSettings.json ファイルの内容が反映されます。

  2. エディターで [JSON の編集] リンクを選択します。 この選択によって、ビューが未加工の JSON に切り替わります。

  3. "configurePresets":内の"windows-base" プリセットに次のスニペットを追加して、Address Sanitizer を有効にします。

    "environment": {
      "CFLAGS": "/fsanitize=address",
      "CXXFLAGS": "/fsanitize=address"
    }
    

    "configurePresets" その後、次のようになります。

        "configurePresets": [
          {
            "name": "windows-base",
            "hidden": true,
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "installDir": "${sourceDir}/out/install/${presetName}",
            "cacheVariables": {
              "CMAKE_C_COMPILER": "cl.exe",
              "CMAKE_CXX_COMPILER": "cl.exe"
            },
            "condition": {
              "type": "equals",
              "lhs": "${hostSystemName}",
              "rhs": "Windows"
            },
            "environment": {
              "CFLAGS": "/fsanitize=address",
              "CXXFLAGS": "/fsanitize=address"
            }
          },
    
  4. 新しい CMake プロジェクトで既定で有効になっているエディット コンティニュが指定されている (/ZI) 場合、アドレスサニタイザーは機能しません。 CMakeLists.txtで、set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"で始まる行をコメント アウト (プレフィックスに #) します。 その後、その行は次のようになります。

    # set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
    
  5. Ctrl + S を入力して、この JSON ファイルを保存します。

  6. CMake キャッシュ ディレクトリをクリアし、Visual Studio メニューから [ Project>Delete cache and Reconfigure を選択して再構成します。 キャッシュ ディレクトリをクリアして再構成するように求めるプロンプトが表示されたら、[ Yes を選択します。

  7. ソース ファイルの内容 (たとえば、 CMakeProject1.cpp) を次のように置き換えます。

    // CMakeProject1.cpp : Defines the entry point for the application
    
    #include <stdio.h>
    
    int x[100];
    
    int main()
    {
        printf("Hello!\n");
        x[100] = 5; // Boom!
        return 0;
    }
    
  8. F5 を選択して、デバッガーで再コンパイルして実行します。

    このスクリーンショットは、CMake ビルドからのエラーをキャプチャします。

AddressSanitizer クラッシュ ダンプ

AddressSanitizer では、クラウドおよび分散ワークフローで使用するための新機能が導入されました。 この機能により、IDE で AddressSanitizer エラーをオフラインで表示できます。 エラーはソースの上に重なって表示されるので、ライブのデバッグ セッションで体験するのと同じように見えます。

これらの新しいダンプ ファイルを使用すると、バグを解析するときの効率が向上します。 リモート データを再実行したり探したり、オフラインになったコンピューターを探したりする必要がなくなります。

別のコンピューターの Visual Studio で後で表示できる新しい種類のダンプ ファイルを生成するには:

set ASAN_SAVE_DUMPS=MyFileName.dmp

Visual Studio 16.9 以降から、*.dmp ファイルに格納された正確に診断されたエラーを、ソース コードの最上部に表示できます。

この新しいクラッシュ ダンプ機能により、 クラウドベースのワークフロー、または分散テストが可能になります。 また、任意のシナリオで詳細でアクション可能なバグを報告するためにも使用できます。

エラーの例

AddressSanitizer は、さまざまな種類のメモリ誤用エラーを検出できます。 AddressSanitizer (/fsanitize=address) コンパイラ オプションを使用してコンパイルされたバイナリを実行するときに報告される数多くのランタイム エラーを次に示します。

例の詳細については、「AddressSanitizer エラーの例」を参照してください。

Clang 12.0 との違い

MSVC は現在 Clang 12.0 と、次の 2 つの機能領域で異なります。

  • stack-use-after-scope - この設定は既定でオンであり、オフにすることはできません。
  • stack-use-after-return - この機能には追加のコンパイラ オプションが必要であり、ASAN_OPTIONS を設定するだけで使用することはできません。

これらの決定は、この最初のバージョンを提供するために必要なテスト マトリックスを減らすために行いました。

Visual Studio 2019 16.9 で誤検知につながる可能性がある機能は含まれませんでした。 その分野では、数十年もの既存のコードとの相互運用を検討するときに必要な効果的なテストの整合性が適用されました。 他の機能が、後のリリースで検討される可能性があります。

詳細については、「 Building for AddressSanitizer with MSVCを参照してください。

既存の業界ドキュメント

AddressSanitizer テクノロジのこれらの言語とプラットフォーム依存型実装については、広範なドキュメントが既に存在します。

AddressSanitizer に関する影響力の大きい論文で、実装について説明しています。

関連項目

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