介绍
AddressSanitizer
简称asan或者sanitizer.
lvm提供了内存调试工具,例如地址sanitizer、内存sanitizer。
目前AddressSanitizer能够发现如下问题:
- Out-of-bounds accesses to heap, stack and globals
- Use-after-free
- Use-after-return (runtime flag ASAN_OPTIONS=detect_stack_use_after_return=1)
- Use-after-scope (clang flag -fsanitize-address-use-after-scope)
- Double-free, invalid free
- Memory leaks (experimental)
准备工作
要使用sanitizer,需要从llvm svn中把compiler-rt
下载下来
···
cd llvm/project
svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
···
然后重新编译构建llvm(正如之前的编译安装),就能获得所需要的运行时库了。
详细步骤
我们以下的程序为例
int main(){
int a[5];
int index=6;
int retval=a[index];
return retval;
}
使用在编译程序时加上-fsanitize=address -fno-omit-frame-pointer
两个编译选项即可,需要说明的是要使用系统自带的内存管理库,不能使用第三方的内存管理库,因为这个功能要拦截malloc,free等标准函数。
gcc几个常用编译选项如下:
-fsanitize=address
开启地址越界检查功能-fno-omit-frame-pointer
开启后,可以出界更详细的错误信息-fsanitize=leak
开启内存泄露检查功能
我们此处使用
g++ mem.c -fsanitize=address -g
也可以使用clang -fsanitize=address mem.c
(但好像需要debug版本,以及compiler-rt)
设置环境变量(实测非必要)
export ASAN_SYMBOLIZER_PATH=/usr/local/bin/llvm-symbolizer
export ASAN_OPTIONS=use_sigaltstack=1:verbosity=0:handle_segv=1:allow_user_segv_handler=1:detect_leaks=1
然后使用如下执行地址sanitizer
./a.out
执行以后可以看到详细的报告
./a.out
=================================================================
==7494==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe7d214fd8 at pc 0x559f0634e23e bp 0x7ffe7d214f80 sp 0x7ffe7d214f70
READ of size 4 at 0x7ffe7d214fd8 thread T0
#0 0x559f0634e23d in main /home/happy/work/mem.c:4
#1 0x7ff0949a7b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)
#2 0x559f0634e0b9 in _start (/home/happy/work/a.out+0x10b9)
Address 0x7ffe7d214fd8 is located in stack of thread T0 at offset 56 in frame
#0 0x559f0634e184 in main /home/happy/work/mem.c:1
This frame has 1 object(s):
[32, 52) 'a' <== Memory access at offset 56 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 /home/happy/work/mem.c:4 in main
Shadow bytes around the buggy address:
0x10004fa3a9a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004fa3a9b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004fa3a9c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004fa3a9d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004fa3a9e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10004fa3a9f0: 00 00 00 00 f1 f1 f1 f1 00 00 04[f2]00 00 00 00
0x10004fa3aa00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004fa3aa10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004fa3aa20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004fa3aa30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004fa3aa40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==7494==ABORTING
Comments | NOTHING