AddressSanitizer

概要

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

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

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

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

AddressSanitizer は、Visual Studio プロジェクト システム、CMake ビルド システム、IDE と統合されています。 プロジェクトで AddressSanitizer を有効にするには、プロジェクトのプロパティを設定するか、ひとつの追加コンパイラ オプション /fsanitize=address を使用します。 新しいオプションは、x86 および x64 のすべてのレベルの最適化および構成と互換性があります。 ただし、エディット コンティニュ、インクリメンタル リンクおよび /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 サポートを有効にします。 ツールの取得ツール>と機能を使用して、Visual Studio メイン メニューからインストーラーを開くことができます。Visual Studio インストーラーから既存の Visual Studio インストールで [変更] を選択して、次の画面にアクセスします。

Screenshot of the Visual Studio Installer. The C++ AddressSanitizer component, under the Optional section, is highlighted.

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 を使用して行います

Screenshot of a command prompt showing the command to compile with AddressSanitizer options. The command is: `cl main.cpp -faanitize-address /Zi`.

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

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

Screenshot of the debugger showing a basic global overflow error.

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

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

  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 を有効にするには、ソリューション エクスプローラーでプロジェクトを右クリックし、[プロパティ] を選択します[プロパティ ページ] ダイアログで、[構成プロパティ]>[C/C++]>[全般] を選択してから、[AddressSanitizer を有効にする] プロパティを変更します。 [OK] を選択して変更を保存します。

Screenshot of the Property Pages dialog showing the Enable AddressSanitizer property.

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

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

Screenshot of the debugger showing a global buffer overflow error.

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

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

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

    Screenshot of the CMake configuration dropdown. It displays options like x64 Debug, x64 Release, and so on. At the bottom of the list, Manage Configurations... is highlighted.

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

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

  3. 次のスニペットをプリセットに "windows-base" 追加し、内部 "configurePresets": で 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. エディット コンティニュが指定されている場合、アドレスサニタイザーは機能しません。/ZIこれは、新しい CMake プロジェクトに対して既定で有効になっています。 で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]\(プロジェクト>の削除キャッシュと再構成\) を選択して再構成します。 キャッシュ ディレクトリをクリアして再構成するプロンプトが表示されたら、[はい] を選択します。

  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 ビルドからのエラーをキャプチャします。

    Screenshot of an exception that says: Address Sanitizer Error: Global buffer overflow. In the background, address sanitizer output is visible in command window.

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

詳細については、「MSVC を使用した AddressSanitizer のビルド」を参照してください

既存の業界ドキュメント

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

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

関連項目

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