Address Sanitizer

· 488 words · 1 minute read

N 年前,调试 C/C++ 内存问题一般会选择用valgrind 或者efence. 目前 Address Sanitizer (ASan) 居多, 它已经被集成进了 LLVM 以及 GCC, 用来比较方便。


访问越界 🔗

比如,下面的代码:

int main() {
    int a[2] = {1, 0};
    return a[2];
}

编译运行之:1

$ gcc -fsanitize=address -ggdb -o t1 t1.c
$ ./t1
==1057331==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd3ddaa1d8 at pc 0x00000040091d bp 0x7ffd3ddaa1a0 sp 0x7ffd3ddaa190
READ of size 4 at 0x7ffd3ddaa1d8 thread T0
	#0 0x40091c in main /data/t1.c:3
	#1 0x7f24e38bed84 in __libc_start_main (/lib64/libc.so.6+0x3ad84)
	#2 0x40073d in _start (/data/t1+0x40073d)

Address 0x7ffd3ddaa1d8 is located in stack of thread T0 at offset 40 in frame
	#0 0x400805 in main /data/t1.c:1

  This frame has 1 object(s):
	[32, 40) 'a' <== Memory access at offset 40 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
	  (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /data/t1.c:3 in main

还会额外打印堆栈的详细信息,就不贴了。2

Use after free() 🔗

比如,下面的代码:

#include <stdlib.h>

int main() {
    int* p = malloc(16);
    free(p);
    return *p;
}

编译运行之:

$ gcc -fsanitize=address -ggdb -o t2 t2.c
==1057418==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000010 at pc 0x0000004007df bp 0x7ffc2c7dfb70 sp 0x7ffc2c7dfb60
READ of size 4 at 0x602000000010 thread T0
	#0 0x4007de in main /data/t2.c:6
	#1 0x7ff86c881d84 in __libc_start_main (/lib64/libc.so.6+0x3ad84)
	#2 0x4006cd in _start (/data/t2+0x4006cd)

0x602000000010 is located 0 bytes inside of 16-byte region [0x602000000010,0x602000000020)
freed by thread T0 here:
	#0 0x7ff86ccfb7f0 in __interceptor_free (/lib64/libasan.so.5+0xef7f0)
	#1 0x4007a7 in main /data/t2.c:5
	#2 0x7ff86c881d84 in __libc_start_main (/lib64/libc.so.6+0x3ad84)

previously allocated by thread T0 here:
	#0 0x7ff86ccfbbb8 in __interceptor_malloc (/lib64/libasan.so.5+0xefbb8)
	#1 0x400797 in main /data/t2.c:4
	#2 0x7ff86c881d84 in __libc_start_main (/lib64/libc.so.6+0x3ad84)

SUMMARY: AddressSanitizer: heap-use-after-free /data/t2.c:6 in main

Memory Leak 🔗

也就是光分配、不释放。这里就不贴示例了。3

标记某个函数不进行分析 🔗

__attribute__((no_sanitize_address)

ASAN_OPTIONS 🔗

发现问题时,立刻终止进程:

$ export ASAN_OPTIONS='abort_on_error=1'

更多编译时、运行时控制选项,参考文档


  1. 默认动态链接 libasan, 可以加 ‘-static-libasan’ 指定静态链接 asan. ↩︎

  2. 参考 https://fuzzing-project.org/tutorial2.html ↩︎

  3. 参考 https://www.osc.edu/resources/getting_started/howto/howto_use_address_sanitizer ↩︎

c++
comments powered by Disqus