好记性不如铅笔头

linux, 操作系统

linux地址消毒(Address Sanitizer)简单笔记

本文参考【 https://www.jianshu.com/p/3a2df9b7c353 】,有大量删改。

Address Sanitizer(ASan)是一个快速的内存错误检测工具。这里说明它的用法。

参考资料【 https://github.com/google/sanitizers/wiki/AddressSanitizer

简介

Address Sanitizer(ASan)是一个快速的内存错误检测工具。它非常快,只拖慢程序两倍左右(比起Valgrind快多了)。它包括一个编译器instrumentation模块和一个提供malloc()/free()替代项的运行时库。

从gcc 4.8开始,AddressSanitizer成为gcc的一部分。当然,要获得更好的体验,最好使用4.9及以上版本,因为gcc 4.8的AddressSanitizer还不完善,最大的缺点是没有符号信息。

使用步骤

-fsanitize=address选项编译和链接你的程序。
-fno-omit-frame-pointer编译,以得到更容易理解stack trace。
可选择-O1或者更高的优化级别编译

使用实例:
gcc -fsanitize=address -fno-omit-frame-pointer -O1 -g use-after-free.c -o use-after-free

运行use-after-fee。如果发现了错误,就会打印出类似下面的信息:

==9901==ERROR: AddressSanitizer: heap-use-after-free on address 0x60700000dfb5 
  at pc 0x45917b bp 0x7fff4490c700 sp 0x7fff4490c6f8
READ of size 1 at 0x60700000dfb5 thread T0
    #0 0x45917a in main use-after-free.c:5
    #1 0x7fce9f25e76c in __libc_start_main /build/buildd/eglibc-2.15/csu/libc-start.c:226
    #2 0x459074 in _start (a.out+0x459074)
0x60700000dfb5 is located 5 bytes inside of 80-byte region [0x60700000dfb0,0x60700000e000)
freed by thread T0 here:
    #0 0x4441ee in __interceptor_free projects/compiler-rt/lib/asan/asan_malloc_linux.cc:64
    #1 0x45914a in main use-after-free.c:4
    #2 0x7fce9f25e76c in __libc_start_main /build/buildd/eglibc-2.15/csu/libc-start.c:226
previously allocated by thread T0 here:
    #0 0x44436e in __interceptor_malloc projects/compiler-rt/lib/asan/asan_malloc_linux.cc:74
    #1 0x45913f in main use-after-free.c:3
    #2 0x7fce9f25e76c in __libc_start_main /build/buildd/eglibc-2.15/csu/libc-start.c:226
SUMMARY: AddressSanitizer: heap-use-after-free use-after-free.c:5 main

第一部分(ERROR)指出错误类型是heap-use-after-free;
第二部分(READ), 指出线程名thread T0,操作为READ,发生的位置是use-after-free.c:5。
该heapk块之前已经在use-after-free.c:4被释放了;
该heap块是在use-fater-free.c:3分配
第三部分 (SUMMARY) 前面输出的概要说明。

错误类型

3.1 heap use after free 释放后使用
3.2 heap buffer overflow 堆缓存访问溢出
3.2 stack buffer overflow 栈缓存访问溢出
3.3 global buffer overflow 全局缓冲访问溢出
3.4 use after return
3.5 use after scope
3.6 initializations order bugs
3.7 memory leaks 内存泄露
目前,并不是所有的平台都默认检测内存泄露,可以指定运行时ASAN_OPTIONS开启如下:
ASAN_OPTIONS=detect_leaks=1 yourapp
而且不是所有的平台支持检测内存泄露,比如ARM,就会得到这样的提示:
==1901==AddressSanitizer: detect_leaks is not supported on this platform.

编译和运行选项

参考【 https://blog.csdn.net/hanlizhong85/article/details/78076668
https://github.com/google/sanitizers/wiki/AddressSanitizerFlags

1、编译选项

1.1 Gcc编译选项
# -fsanitize=address:开启内存越界检测
# -fsanitize-recover=address:一般后台程序为保证稳定性,不能遇到错误就简单退出,而是继续运行,采用该选项支持内存出错之后程序继续运行,需要叠加设置ASAN_OPTIONS=halt_on_error=0才会生效;若未设置此选项,则内存出错即报错退出
举例:ASAN_CFLAGS += -fsanitize=address -fsanitize-recover=address

# -fno-stack-protector:去使能栈溢出保护
# -fno-omit-frame-pointer:去使能栈溢出保护
# -fno-var-tracking:默认选项为-fvar-tracking,会导致运行非常慢
# -g1:表示最小调试信息,通常debug版本用-g即-g2
举例:ASAN_CFLAGS += -fno-stack-protector -fno-omit-frame-pointer -fno-var-tracking -g1

1.2 Ld链接选项
ASAN_LDFLAGS += -fsanitize=address -g1
如果使用gcc链接,此处可忽略。

2、ASAN运行选项

2.1 ASAN_OPTIONS设置
ASAN_OPTIONS是Address-Sanitizier的运行选项环境变量
# halt_on_error=0:检测内存错误后继续运行
# detect_leaks=1:使能内存泄露检测
# malloc_context_size=15:内存错误发生时,显示的调用栈层数为15
# log_path=/home/xos/asan.log:内存检查问题日志存放文件路径
# suppressions=$SUPP_FILE:屏蔽打印某些内存错误
举例:export ASAN_OPTIONS=halt_on_error=0:use_sigaltstack=0:detect_leaks=1:malloc_context_size=15:log_path=/home/xos/asan.log:suppressions=$SUPP_FILE

除了上述常用选项,以下还有一些选项可根据实际需要添加:
# detect_stack_use_after_return=1:检查访问指向已被释放的栈空间
# handle_segv=1:处理段错误;也可以添加handle_sigill=1处理SIGILL信号
# quarantine_size=4194304:内存cache可缓存free内存大小4M
举例:ASAN_OPTIONS=${ASAN_OPTIONS}:verbosity=0:handle_segv=1:allow_user_segv_handler=1:detect_stack_use_after_return=1:fast_unwind_on_fatal=1:fast_unwind_on_check=1:fast_unwind_on_malloc=1:quarantine_size=4194304

Leave a Reply

10 + 8 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据