gcc で sanitizer を使う

tl;dr

$ gcc -fsanitize=undefined -fno-sanitize-recover=all foo.c
$ UBSAN_OPTIONS='verbosity=1:abort_on_error=1:handle_abort=2:disable_coredump=0' ./a.out

詳細

gcc では asan (address sanitizer), ubsan (undefined behavior sanitizer) といった sanitizer が利用できる。 (clang でも利用可能。細かい違いは不明)

CFLAGS/CXXFLAGS, LDFLAGS の両方に -fsanitize=undefined を付けると ubsan が有効になる。また、-fno-sanitize-recover=all を付けると sanitizer 側でのエラー回復を無効化できる。単にコアダンプしてほしい場合などに有効。

さらに、sanitizer がエラーを報告する際の挙動を環境変数 ASAN_OPTIONS, UBSAN_OPTIONS で制御できる。書式は a=1:b=0:c=1 のように、<変数名>=<値> をコロンで区切る。 変数は全 sanitizer 共通のものとそうでないものがある。今のところこれらに関するドキュメントがあまり見当たらないため、ソースを頑張って読むしかない模様:

有用そうな変数を挙げておく:

  • abort_on_error: 1 でエラー落ちする際に abort() を使う(デフォルトは _exit())。
  • disable_coredump: 0 でコアダンプする。64bit ではデフォルトで 1 になっている (巨大なコアを吐くのを防ぐためらしい)。 プログラム側でシグナルハンドラをいじっている場合、これを 0 にしてもコアダンプ しないことがある。その場合は handle_abort を併用する。
  • handle_abort: 2 でプログラム側での SIGABRT ハンドラ登録を禁止する。強制的に コアダンプさせるのに使える。
  • verbosity: 0 から 2 まで。1 以上のとき、UBSAN_OPTIONS に無効なオプション が含まれていたらエラー落ちする際にその旨警告する。
  • print_stacktrace: UBSAN 用。1 でスタックトレースを吐く。