|
AddressSanitizer(ASAN),ASAN(AddressSanitizer 的缩写)是一款 面向 C/C++语言的内存错误问题检查工具,可以检测如下内存问题:
• 使用已释放内存(野指针)
• 堆内存越界(读写)
• 栈内存越界(读写)
• 全局变量越界(读写)
• 函数返回局部变量
• 内存泄漏
ASAN 工具主要由两部分组成:
1.运行时库:
运行时库(libasan.so.x)会接管 malloc 和free 函数。malloc 执行完后,已分配内存的前后(称为“红区”)会被标记为“中毒”状态,而释放的内存则会被隔离起来(暂 时不会分配出去)且也会被标记为“中毒”状态。
2.编译器插桩模块:
加了 ASAN 相关的编译选项后,代码中的每一次内存访问操作都会被编译器修改 为如下方式:
编译前:
编译后:
上节也介绍过一款传统的内存问题检测工具 Valgrind,但是程序中跑 Valgrind 其会极 大的降低程序运行速度,大约降低 10 倍,而跑 AddressSanitizer 大约只降低 2 倍! 与 valgrind 相比 asan 消耗非常低,甚至可以直接在生产环境中启用 asan 排查跟踪内存问题。
1.AddressSanitizer 安装
ASAN 早先是 LLVM 中的特性,后被加入 gcc4.8,成为 gcc 的一部分,但不支持符 号信息,无法显示出问题的函数和行数。从 4.9 开始,gcc 支持 AddressSanitizer 的 所有功能。因此 gcc 4.8 以上版本使用 ASAN 时不需要安装第三方库,通过在编译时指 定编译 CFLAGS 即可打开开关。
如果使用 AddressSanitizer 时报错则需要先安装,Ubuntu 安装命令为:
sudo apt-get install libasan0
CentOS 安装命令:
sudo yum install libasan
2.AddressSanitizer 的使用选项
gcc/g++编译选项:
-fsanitize=address:开启内存越界检测
-fsanitize-recover=address:一般后台程序为保证稳定性,不能遇到错误就简单退 出,而是继续运行,采用该选项支持内存出错之后程序继续运行,需要叠加设置 ASAN_OPTIONS= halt_on_error=0 才会生效;若未设置此选项,则内存出错即报错退出
-fno-stack-protector:去使能栈溢出保护
-fno-omit-frame-pointer:去使能栈溢出保护
-g1:表示最小调试信息,通常 debug 版本用-g 即-g2
ASAN_OPTIONS 环境变量设置选项:
halt_on_error=0:检测内存错误后继续运行
detect_leaks=1:使能内存泄露检测
malloc_context_size=15:内存错误发生时,显示的调用栈层数为 15
log_path=/home/asan.log:内存检查问题日志存放文件路径
例如:
export ASAN_OPTIONS=halt_on_error=0:use_sigaltstack=0:detect_leaks=1:malloc _context_size=15:log_path=/home/asan.log
3.AddressSanitizer 的使用示例
我们看下面一段程序
很明显存在内存泄漏,p 开始指向一片 malloc 的内存,然后没有释放又指向了其他内 存。接着我们来带上 ASAN 工具编译它,首先设置一下 ASAN_OPTIONS 环境变量
然后使用env查看设置是否成功
设置好环境变量我们再来带上 ASAN 工具编译我们的程序
然后运行,就会在我们环境变量设置地方保存一个文件,后缀加上了进程号:
我们查看里面的内容:
上面记录了我们这个程序的错误是ERROR后面的内容 detected memory leaks,说明有内存泄漏。错误类型有如下一些:
(heap) use after free 释放后使用
heap buffer overflow 堆缓存访问溢出
stack buffer overflow 栈缓存访问溢出
global buffer overflow 全局缓冲访问溢出
use after return
use after scope
initializations order bugs
memory leaks 内存泄露
#1是内存分配的地方,#2是使用的地方。然后后面就是导致程序泄漏的位置,是一个进程的内存偏移形式,我们可以在编译时加-g选项,就可以定位出代码位置,例如:
上面就是加上-g选项后的结果,可以看到告知了我们泄漏内存分配的地方和使用的地方。
不过需要注意的是如果发生错误的程序在动态库文件中,那么通过上面的方式就无法定位具体行数了,那怎么找到着个泄漏点呢?如果这个库是我们自己可以去编译的,那么在编译库的时候也加上-g选项就好了,如果这个库是别人提供的,那么就需要利用addr2line工具去做一个转换了,具体方式请遇到问题后去再去学习下怎么使用addr2line命令吧,用法很简单,下载好了直接使用命令就行了。
来源:http://www.yidianzixun.com/article/0lVGc3Bb
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|