エラーを出す方法メモ
$ gcc -Wall -Wextra -O2 -c hogehoge.c
最適化オプションが必須、他はおまけ。
O1
ではでない、O2
もしくはO3
などではでる。特に意味もないのでO2
でいいんじゃないかな(無知)。
12/1追記 debianで失敗
AdressSanitizer/LeakSanitizerというものでできるらしい
// list_boundary.c
#include<stdio.h>
#include<stdlib.h>
#define N 10
void bug(void){
int *test_buff = (int*)malloc(sizeof(int) * N);
test_buff[N] = 10; // error
}
int main( void ){
printf("start\n");
bug();
printf("end\n");
return 0;
}
このコードで試す。
$ gcc -g -fsanitize=address list_boundary.c
$ a.out
start
=================================================================
==35538==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6040000003f8 at pc 0x00010aa05d5b bp 0x7ffee51fa7b0 sp 0x7ffee51fa7a8
WRITE of size 4 at 0x6040000003f8 thread T0
#0 0x10aa05d5a in bug list_boundary.c:8
#1 0x10aa05d84 in main list_boundary.c:16
#2 0x7fff5b0d53d4 in start (libdyld.dylib:x86_64+0x163d4)
0x6040000003f8 is located 0 bytes to the right of 40-byte region [0x6040000003d0,0x6040000003f8)
allocated by thread T0 here:
#0 0x10aa7e83f in wrap_malloc (libasan.5.dylib:x86_64+0x7683f)
#1 0x10aa05d11 in bug list_boundary.c:7
#2 0x10aa05d84 in main list_boundary.c:16
#3 0x7fff5b0d53d4 in start (libdyld.dylib:x86_64+0x163d4)
SUMMARY: AddressSanitizer: heap-buffer-overflow list_boundary.c:8 in bug
Shadow bytes around the buggy address:
0x1c0800000020: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 05
0x1c0800000030: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 05
0x1c0800000040: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 07
0x1c0800000050: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa
0x1c0800000060: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa
=>0x1c0800000070: fa fa 00 00 00 00 00 05 fa fa 00 00 00 00 00[fa]
0x1c0800000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c0800000090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c08000000a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c08000000b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c08000000c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==35538==ABORTING
void bug(void){
int *test_buff = (int*)malloc(sizeof(int) * N);
test_buff[N-1] = 10; // modified
}
メモリーリークも検出できる。終了時に判定されるため、アクセスエラーを拾って終了しないように修正する。
さあ以下で実行。
$ gcc -g -fsanitize=address list_boundary.c
$ ASAN_OPTIONS=detect_leaks=1 a.out
start
end
=================================================================
==35595==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 40 byte(s) in 1 object(s) allocated from:
#0 0x10c72e83f in wrap_malloc (libasan.5.dylib:x86_64+0x7683f)
#1 0x10c6b4d2b in bug list_boundary.c:7
#2 0x10c6b4d92 in main list_boundary.c:15
#3 0x7fff5b0d53d4 in start (libdyld.dylib:x86_64+0x163d4)
SUMMARY: AddressSanitizer: 40 byte(s) leaked in 1 allocation(s).
できた。なんて便利。
参考
- https://gcc.gnu.org/ml/gcc-patches/2013-11/msg01874.html
- https://clang.llvm.org/docs/AddressSanitizer.html