内存问题检查工具——Address Sanitizer(ASAN)
Address Sanitizer(ASAN)是gcc自带的内存问题检查工具,比较轻量级,非常适合单元测试时检查内存问题。使用也比较简单,只需要在编译时候加“-fsanitize=address -fno-omit-frame-pointer” 即可。若想更精确查看到源码位置,可以加 “-g” 编译debug版本。下面给出几个简单案例。
案例一:内存泄漏
#include<stdio.h>
#include<stdlib.h>
int main() {
void* buf = malloc(1024);
return 0;
}
编译:“gcc hello.c -fsanitize=address -fno-omit-frame-pointer -g” ,然后直接执行 ./a.out 即可:
=================================================================
==3440094==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1024 byte(s) in 1 object(s) allocated from:
#0 0x7f1530026808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x55c8c0e8119e in main /home/loongknown/test/hello.c:5
#2 0x7f152fd4b082 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 1 allocation(s).
案例二:读越界
#include<stdio.h>
#include<stdlib.h>
int main() {
int a[10] = {0};
int x = a[10];
return 0;
}
编译和执行同上:
=================================================================
==3440706==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcdc0fdf68 at pc 0x55c54dad2352 bp 0x7ffcdc0fdef0 sp 0x7ffcdc0fdee0
READ of size 4 at 0x7ffcdc0fdf68 thread T0
#0 0x55c54dad2351 in main /home/loongknown/test/hello.c:6
#1 0x7f70259e6082 in __libc_start_main ../csu/libc-start.c:308
#2 0x55c54dad212d in _start (/home/loongknown/test/a.out+0x112d)
Address 0x7ffcdc0fdf68 is located in stack of thread T0 at offset 88 in frame
#0 0x55c54dad21f8 in main /home/loongknown/test/hello.c:4
This frame has 1 object(s):
[48, 88) 'a' (line 5) <== Memory access at offset 88 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/loongknown/test/hello.c:6 in main
Shadow bytes around the buggy address:
0x10001b817b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001b817ba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001b817bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001b817bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001b817bd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10001b817be0: 00 00 f1 f1 f1 f1 f1 f1 00 00 00 00 00[f3]f3 f3
0x10001b817bf0: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001b817c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001b817c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001b817c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001b817c30: 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
==3440706==ABORTING
越界源码位置和越界的地址都有清晰的显示。
案例三:写越界
#include<stdio.h>
#include<stdlib.h>
int main() {
int a[10] = {0};
a[10] = 1;
return 0;
}
同上编译和执行:
=================================================================
==3441478==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd938896e8 at pc 0x55e6f9bc8352 bp 0x7ffd93889680 sp 0x7ffd93889670
WRITE of size 4 at 0x7ffd938896e8 thread T0
#0 0x55e6f9bc8351 in main /home/loongknown/test/hello.c:6
#1 0x7fd974ba6082 in __libc_start_main ../csu/libc-start.c:308
#2 0x55e6f9bc812d in _start (/home/loongknown/test/a.out+0x112d)
Address 0x7ffd938896e8 is located in stack of thread T0 at offset 88 in frame
#0 0x55e6f9bc81f8 in main /home/loongknown/test/hello.c:4
This frame has 1 object(s):
[48, 88) 'a' (line 5) <== Memory access at offset 88 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/loongknown/test/hello.c:6 in main
Shadow bytes around the buggy address:
0x100032709280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100032709290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000327092a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000327092b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000327092c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1000327092d0: 00 00 f1 f1 f1 f1 f1 f1 00 00 00 00 00[f3]f3 f3
0x1000327092e0: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000327092f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100032709300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100032709310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100032709320: 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
==3441478==ABORTING
推荐大家尝试使用!本文结束。