Work
Travel
Various
C++ サニタイザー
以下は、実用的で移植性が高く、導入の手間が少ない、複数のディストリビューションで使えるおすすめのサニタイザー一覧です。
integer、memory、HWASan などのその他のサニタイザーは、実用性がそれほど高くない、
あるいはディストリビューションやコンパイラによって実装がサポートされていなかったり、結果が異なったりする場合があるなどの理由で、この一覧には含めていません。
address: ASan — AddressSanitizer (-fsanitize=address)
目的: 実行時にメモリ安全性に関するバグを検出します。
- 範囲外の読み書き(ヒープ/スタック/グローバル)
- use-after-free(解放後の使用)
- 二重解放/不正な解放
- 一部の use-after-return/use-after-scope 検出モード(ツールチェーン依存)
典型的な用途:「クラッシュやメモリ破損を素早く見つける」。
典型的な検出内容
- ヒープバッファのオーバーフロー/アンダーフロー
- スタックバッファのオーバーフロー/アンダーフロー
- use-after-free
- use-after-return/use-after-scope(コンパイラオプションによる)
- 二重解放、不正な解放、一部のアロケータ誤用
仕組み(概念的に)
- ロード/ストアを計装し、シャドウメモリと、確保領域の周囲に配置してアクセス禁止としてマークしたレッドゾーンを用いて、範囲外アクセスや UAF を素早く検出します。
注意点
- オーバーヘッド: 通常は中程度(多くの場合、実行時間が 1.5〜3 倍になり、メモリ使用量も増加)。
- 非互換性: 実用上、ASan と TSan は同じバイナリで併用できません。別々のビルドモードとして扱ってください。
- 誤検出: まれですが、カスタムアロケータや低レベルの技巧を使う場合、適切にアノテーションしないと発生することがあります。
thread: TSan — ThreadSanitizer (-fsanitize=thread)
データ競合やその他の並行処理の問題を検出します:
- 同期されていない並行アクセス(少なくとも一方が書き込み)
- 競合時のスタックトレースと同期に関する情報を報告
典型的な用途:「スレッド安全性を検証する」。 注: 通常は ASan とは別のビルドで実行します。
目的: データ競合と、その他いくつかの並行処理に関するバグを検出します。
典型的な検出内容
- データ競合(同期されていない並行アクセス、少なくとも一方が書き込み)
- ミューテックスやアトミック操作に関する誤用パターン(ランタイム依存)
- デッドロック関連の診断が出ることもありますが、主な用途は競合の検出です。
仕組み
- メモリアクセスと同期操作を計装し、happens-before モデルを構築して、競合するアクセスを報告します。
注意点
- オーバーヘッド: 大きい(多くの場合、実行時間が 5〜15 倍になり、メモリオーバーヘッドも大きい)。
- 非互換性: 一般に単一のビルドで ASan/LSan/UBSan とは併用しません。専用の「tsan」構成を使ってください。
- 効果を得るには、コードの大半(理想的には主要なサードパーティライブラリも)を TSan の計装を有効にしてビルドする必要があります。
undefined UBSan — UndefinedBehaviorSanitizer (-fsanitize=undefined とサブチェック群)
C/C++ における未定義動作を検出します:
- 符号付き整数のオーバーフロー(有効にした場合)
- 不正なシフト(シフト量が負、または大きすぎる)
- アラインメント要件を満たさないアクセス
- 不正な vptr(一部のモード)、範囲外の enum 値など
典型的な用途:「クラッシュしない場合でも誤りである UB を検出する」。
目的: 実行時に未定義動作(言語/ABI 規則の違反)を検出します。
典型的な検出内容(例)
- 符号付き整数のオーバーフロー(有効にした場合)
- 不正なシフト(シフト量が負、またはビット幅以上)
- アラインメント要件を満たさないポインタの間接参照
- 一部の状況における null ポインタの問題(オプション依存)
- 不正な enum 値、vptr チェックなど(フラグ依存)
仕組み
- 特定の UB カテゴリに対するチェックを挿入し、実行時にトラップを発生させるか、問題を報告します。
注意点
- 「UBSan」は実際には複数のチェックの集合であり、実行されるチェックは指定したフラグによって異なります。
- 一部のチェックは、意図的に「無害な UB」パターンに依存しているコードベースではノイズが多くなることがあります。
leak LSan — LeakSanitizer (-fsanitize=leak または ASan のリーク検出)
メモリリーク(プログラム終了時に到達不能となる、解放されていない確保領域)を検出します。
典型的な用途:「長時間稼働するサービスやテストで、気づかないうちにリークが発生するのを防ぐ」。 Linux では ASan の一部として使われることが多いです。
目的: メモリリーク(確保されたがプログラム終了時に到達不能なオブジェクト)を検出します。
典型的な検出内容
- リークしたヒープの確保領域
- 呼び出しをインターセプトできる特定のメモリ確保 API によるリーク
仕組み
- プロセス終了時(または要求時)に、メモリの到達可能性を調べる起点となるルートを走査し、一度も解放されず、到達不能となっている確保領域を報告します。
注意点
- リーク検出は、プログラムが「正常に」終了し、メモリ確保がインターセプト可能なアロケータを通じて行われる場合に最も信頼できます。
- Linux では ASan の一部としてワークフローに組み込まれることが多く、多くのチームは「リーク専用」ビルドを分けるのではなく、リーク検出を有効にした ASan を実行します。