gccで、配列の範囲を超えてアクセスしてる人を探してぶっ殺したい。
そのためにはgccの ASAN(Address Sanitizer)機能を使う
-fsanitize=address
ソース
#include <stdio.h> int main() { char buf[15]; printf("MAIN\n"); for(int i=0; i<16; i++){ printf("%08X:buf[%d]\n", &buf[i], i); buf[i] = i; } return 0; }
配列が15個しかないのに16回まわるのではみ出る、というサンプルプログラム
実行結果
MAIN 621FF520:buf[0] 621FF521:buf[1] (中略) 621FF52E:buf[14] 621FF52F:buf[15] ================================================================= ==1594509==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd621ff52f at pc 0x55660474d2aa bp 0x7ffd621ff4e0 sp 0x7ffd621ff4d8 WRITE of size 1 at 0x7ffd621ff52f thread T0 #0 0x55660474d2a9 in main /tmp/main.c:9 #1 0x7f68a29f8189 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #2 0x7f68a29f8244 in __libc_start_main_impl ../csu/libc-start.c:381 #3 0x55660474d0e0 in _start (/tmp/a.out+0x10e0) Address 0x7ffd621ff52f is located in stack of thread T0 at offset 47 in frame #0 0x55660474d1b8 in main /tmp/main.c:3 This frame has 1 object(s): [32, 47) 'buf' (line 4) <== Memory access at offset 47 overflows this variable HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-buffer-overflow /tmp/main.c:9 in main
はみ出た時点でABORTする。 ちゃんと何行目ではみ出たかを検知している。
(はみ出なければ何も起きない)
-fsanitize=bounds
配列をはみ出たことだけを検知したいときは bounds を使う。
またこのときは ABORTせずに適当にごまかして先に進めてしまうので、それを回避したいときは
-fno-sanitize-recover=all オプションも指定すると、そこでプログラムが終了する。
コンパイル
gcc -g -fno-sanitize-recover=all -fsanitize=bounds main.c
実行結果
MAIN 9ED8575D:buf[0] 9ED8575E:buf[1] (中略) 9ED8576B:buf[14] 9ED8576C:buf[15] main.c:9:12: runtime error: index 15 out of bounds for type 'char [15]'
情報量が無いしcoreも吐けないので これはまあ使わない
コアダンプの設定
ABORTしたときにcoreを吐かせる方法。
まずそもそもulimitでコアが出るようにした上で、環境変数ASAN_OPTIONSでcoreを吐くように設定する
実行結果
$ ulimit -c unlimited $ export ASAN_OPTIONS=abort_on_error=1:disable_coredump=0:unmap_shadow_on_exit=1 $ ./a.out (中略) ==1594730==ABORTING Aborted (core dumped)
吐かれたcoreには、はみ出しを検知してから実際にABORTするまでの間に ASANの関数がいっぱい挟まるので 解析利用時には最後の8~9層くらいは読み飛ばす
処理能力
3倍くらい遅くなる気がする