clang/gccでメモリチェック

gcc/clangでは気軽に未初期化アクセスや、解放忘れなどのメモリチェック機能を使うことができます。(残念ながらどちらもWindows (Msys2)環境ではサポートされていないようです)


メモリアクセス違反が発生するコード例

#include <iostream>

int main() {
  int* p1 = new int(1);
  int* p2 = p1;
  std::cout << *p1 << std::endl;
  delete p1;
  std::cout << *p2 << std::endl;  // 解放メモリアクセス違反

  int* p3 = new int[10];
  std::cout << p3[5] << std::endl;  // 未初期化メモリアクセス

  int* p4 = new int(5);  // メモリ解放忘れ

  return 0;
}

上記コードは環境にもよるとは思いますが、自分の環境では実行しても正常に終了します。

% clang++ clang_memory_sanitizer.cc
% ./a.out
1
14686864
3

そこで、メモリチェックを有効にするために -fsanitize オプションをつけてコンパイルしてみます. clangでは以下のオプションが使用できるようです

  • -fsanitize=memory … 未初期化メモリアクセスの検出
  • -fsanitizer=address … 解放済みメモリへのアクセス。メモリ解放忘れ
% clang++ -fsanitize=address clang_memory_sanitizer.cc
% ./a.out
1
==3610==ERROR: AddressSanitizer: heap-use-after-free on address ...

より詳細なレポートが必要な場合は以下のようなオプションをつけて最適化を抑制します。公式ページによると、各種メモリチェックにより2倍、3倍と性能が低下するらしいです。

  • -O1 … インライン化抑制
  • -fno-omit-frame-pointer … 常にフレームポインタを保存
  • -fno-optimize-sibling-calls … 末尾呼び出し最適化の禁止

おすすめ