Sanitizersers是一个工具集合,由google开发并开源,项目地址sanitizers 。Sanitizers包括系列工具:
- AddressSanitizer,检测内存访问问题
- MemorySanitizer,检测未初始化内存问题
- ThreadSanitizer,检测线程竞态和死锁问题
- LeakSanitizer,检测内存泄露问题
sanitizers自gcc4.8加入,即编译器自带。相比于我第一个了解的检测工具valgrind,它对程序性能的影响更小,用过valgrind的就知道,使用valgrind后
程序的性能大大降低。大多数的这类工具的基本原理都差不多,就是将原程序的相关函数替换,然后里面加入分析手段。
AddressSanitizer(ASan)
ASan是一个C/C++的内存错误检测工具,它能够检测:
- Use after free,悬空指针引用,也叫野指针引用,即对free后的内存进行存取操作。
- Heap buffer overflow,堆溢出访问,即对堆的操作越界了。
- Stack buffer overflow,栈溢出访问,即对栈的操作越界了。
- Global buffer overflow,全局缓冲区溢出,例如全局的数组这些,反正都是越界访问,只不过位于程序的不同segment。
- Use after return,即栈的野指针,例如A函数调用B函数,A函数有个指针传入到B中,B把它赋值指向了B的一个局部变量,即栈变量,B返回到A后,A操作该指针的错误。
- Use after scope,和Use after return有点类似,C/C++的{}表示一个scope。
- Initialization order bugs
- Memory leaks,内存泄露,AddressSanitizer集成了LeakSanitizer的功能。
Use after free
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *p = malloc(10);
free(p);
p[0] = 1;
return 0;
}
编译时,加上-fsanitize=address选项,选择sanitizers的AddressSanitizer功能,-g有助于输出调试符号信息,例如栈回溯的文件,行号等信息。
编译:
gcc -g -fsanitize=address main.c
./a.out
输出:
=================================================================
==26300==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000010 at pc 0x558bf3e0a22a bp 0x7ffcdcccedf0 sp 0x7ffcdcccede0
WRITE of size 1 at 0x602000000010 thread T0
#0 0x558bf3e0a229 in main /home/thomas/test/ctest/main.c:7
#1 0x7fec69da3082 in __libc_start_main ../csu/libc-start.c:308
#2 0x558bf3e0a10d in _start (/home/thomas/test/ctest/a.out+0x110d)
0x602000000010 is located 0 bytes inside of 10-byte region [0x602000000010,0x60200000001a)
freed by thread T0 here:
#0 0x7fec6a07e40f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:122
#1 0x558bf3e0a1f5 in main /home/thomas/test/ctest/main.c:6
#2 0x7fec69da3082 in __libc_start_main ../csu/libc-start.c:308
previously allocated by thread T0 here:
#0 0x7fec6a07e808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x558bf3e0a1e5 in main /home/thomas/test/ctest/main.c:5
#2 0x7fec69da3082 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: AddressSanitizer: heap-use-after-free /home/thomas/test/ctest/main.c:7 in main
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa[fd]fd fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: 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
==26300==ABORTING
从上面的输出可以看出,一条Use after free的报错,包含几个部分:
- 1.进程号,错误类型,操作是读,还是写,操作的地址,线程号等,以及栈的回溯信息
==26300==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000010 at pc 0x558bf3e0a22a bp 0x7ffcdcccedf0 sp 0x7ffcdcccede0
WRITE of size 1 at 0x602000000010 thread T0
#0 0x558bf3e0a229 in main /home/thomas/test/ctest/main.c:7
#1 0x7fec69da3082 in __libc_start_main ../csu/libc-start.c:308
#2 0x558bf3e0a10d in _start (/home/thomas/test/ctest/a.out+0x110d)
- 2.对此块内存的操作的具体位置,对10字节的内存区域[0x602000000010,0x60200000001a),的第0个字节操作。
0x602000000010 is located 0 bytes inside of 10-byte region [0x602000000010,0x60200000001a)
freed by thread T0 here:
#0 0x7fec6a07e40f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:122
#1 0x558bf3e0a1f5 in main /home/thomas/test/ctest/main.c:6
#2 0x7fec69da3082 in __libc_start_main ../csu/libc-start.c:308
- 3.此块内存区域在那个线程,哪个地方分配的
previously allocated by thread T0 here:
#0 0x7fec6a07e808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x558bf3e0a1e5 in main /home/thomas/test/ctest/main.c:5
#2 0x7fec69da3082 in __libc_start_main ../csu/libc-start.c:308
后面那些信息是AddressSanitizer的内部收集的标记信息。
Heap buffer overflow
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *p = malloc(10);
p[10] = 1;
free(p);
return 0;
}
编译运行,输出,这里需要注意一个内存区域的表达方式region [0x602000000010,0x60200000001a),类似于数学里面区间的表达方式,[
, ]
表示区域包括此地址,
(
、)
表示区域不包括此地址,这里区域右边的0x60200000001a是不包含的,但是操作却写了这个地址的空间,所以报错了。
=================================================================
==26705==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000001a at pc 0x558f03d1f226 bp 0x7ffe54895de0 sp 0x7ffe54895dd0
WRITE of size 1 at 0x60200000001a thread T0
#0 0x558f03d1f225 in main /home/thomas/test/ctest/main.c:6
#1 0x7f95c6524082 in __libc_start_main ../csu/libc-start.c:308
#2 0x558f03d1f10d in _start (/home/thomas/test/ctest/a.out+0x110d)
0x60200000001a is located 0 bytes to the right of 10-byte region [0x602000000010,0x60200000001a)
allocated by thread T0 here:
#0 0x7f95c67ff808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x558f03d1f1e5 in main /home/thomas/test/ctest/main.c:5
#2 0x7f95c6524082 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/thomas/test/ctest/main.c:6 in main
.........
.........
.........
.........
Stack buffer overflow
#include <stdlib.h>
int main(int argc, char *argv[])
{
char p[10];
p[10] = 1;
return 0;
}
编译,运行输出,这里栈的区域表达和堆的不同它使用的是当前栈指针的偏移,例如这里的:
[32, 42) 'p' (line 4) <== Memory access at offset 42 overflows this variable
=================================================================
==26927==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffe0389d7a at pc 0x5577fcfd7289 bp 0x7fffe0389d30 sp 0x7fffe0389d20
WRITE of size 1 at 0x7fffe0389d7a thread T0
#0 0x5577fcfd7288 in main /home/thomas/test/ctest/main.c:5
#1 0x7f97e9d0d082 in __libc_start_main ../csu/libc-start.c:308
#2 0x5577fcfd710d in _start (/home/thomas/test/ctest/a.out+0x110d)
Address 0x7fffe0389d7a is located in stack of thread T0 at offset 42 in frame
#0 0x5577fcfd71d8 in main /home/thomas/test/ctest/main.c:3
This frame has 1 object(s):
[32, 42) 'p' (line 4) <== Memory access at offset 42 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/thomas/test/ctest/main.c:5 in main
........
........
........
........
Global buffer overflow
#include <stdlib.h>
char p[10]={0};
int main(int argc, char *argv[])
{
p[10] = 1;
return 0;
}
编译,运行输出:
=================================================================
==27271==ERROR: AddressSanitizer: global-buffer-overflow on address 0x5632b22930aa at pc 0x5632b2290213 bp 0x7ffeba0b5140 sp 0x7ffeba0b5130
WRITE of size 1 at 0x5632b22930aa thread T0
#0 0x5632b2290212 in main /home/thomas/test/ctest/main.c:5
#1 0x7f90fd627082 in __libc_start_main ../csu/libc-start.c:308
#2 0x5632b229010d in _start (/home/thomas/test/ctest/a.out+0x110d)
0x5632b22930aa is located 0 bytes to the right of global variable 'p' defined in 'main.c:2:6' (0x5632b22930a0) of size 10
SUMMARY: AddressSanitizer: global-buffer-overflow /home/thomas/test/ctest/main.c:5 in main
.......
.......
.......
有个现象是,如果全局变量p
位于bss段,ASan好像检测不出来,即全局变量p不赋初始值时,原因未知。
Use after return
char *p;
void foo()
{
char a[10];
p = &a[0];
}
int main(int argc, char *argv[])
{
foo();
return *p;
}
运行前添加环境变量ASAN_OPTIONS=detect_stack_use_after_return=1
,好像没错误输出,查了相关资料,好像是说这个类型的检测不稳定,有的环境可以,有的不行。
Use after scope
int main()
{
int* p;
{
int a = 1;
p = &a;
}
*p = 2;
return 0;
}
编译额外带上-fsanitize-address-use-after-scope
,运行带上环境变量ASAN_OPTIONS=detect_stack_use_after_scope=0
,我的环境这些都可以
不用带,gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
。编译,运行输出:
=================================================================
==28003==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffe8d7d5280 at pc 0x56336b7972d3 bp 0x7ffe8d7d5240 sp 0x7ffe8d7d5230
WRITE of size 4 at 0x7ffe8d7d5280 thread T0
#0 0x56336b7972d2 in main /home/thomas/test/ctest/main.c:9
#1 0x7fe84a92e082 in __libc_start_main ../csu/libc-start.c:308
#2 0x56336b79710d in _start (/home/thomas/test/ctest/a.out+0x110d)
Address 0x7ffe8d7d5280 is located in stack of thread T0 at offset 32 in frame
#0 0x56336b7971d8 in main /home/thomas/test/ctest/main.c:2
This frame has 1 object(s):
[32, 36) 'a' (line 5) <== Memory access at offset 32 is inside 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-use-after-scope /home/thomas/test/ctest/main.c:9 in main
Initialization order bugs
和C++相关的一个错误,暂不分析
Memory leaks
非常常见的c/c++问题,
#include <stdlib.h>
int main()
{
malloc(10);
return 0;
}
编译,运行输出:
=================================================================
==28220==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 10 byte(s) in 1 object(s) allocated from:
#0 0x7f99d3980808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x55f5ddef019a in main /home/thomas/test/ctest/main.c:4
#2 0x7f99d36a5082 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: AddressSanitizer: 10 byte(s) leaked in 1 allocation(s).
官方的Wiki里面说支持X86_64的linux系统和OS X系统,也就是说ARM系列的不支持?支持情况是:
OS | x86 | x86_64 | ARM | ARM64 | MIPS | MIPS64 | PowerPC | PowerPC64 |
---|---|---|---|---|---|---|---|---|
Linux | yes | yes | yes | yes | yes | yes | ||
OS X | yes | yes | ||||||
iOS Simulator | yes | yes | ||||||
FreeBSD | yes | yes | ||||||
Android | yes | yes | yes | yes |
其他OS/arch的组合支持情况是也可以工作,但是未积极的开发测试。
标签:00,..,start,libc,介绍,fa,Sanitizers,使用,main From: https://www.cnblogs.com/thammer/p/17117286.html