1.背景
写过C++的人都知道,内存管理一直是很头疼的问题。有时候你的程序core了天际,而你却无可奈何,特别是你的服务代码量很大时候,根本无从下手,可能单纯的排查问题都会一周以上。因此我们在存量的基础上,更优雅的方式是借助工具来辅助我们快速定位到问题。
谷歌有一系列Sanitizer官网见https://github.com/google/sanitizers,可以用于定位程序中的系列问题,常用的Sanitizer包括
- Address Sanitizer (ASan) :用于检测内存使用错误
- Leak Sanitizer (LSan) :用于检测内存泄漏
- Thread Sanitizer (TSan) :用于检测多线程间的数据竞争和死锁
- Memory Sanitizer (MSan) :用于检测使用未初始化内存的行为本次主要分享的是ASan的使用
2.ASAN工具
2.1ASAN简介
ASan是Address Sanitizer简称,它是一种基于编译器用于快速检测原生代码中内存错误的工具。简而言之, ASan就是一个用于快速检测内存错误的工具, 目前已经集成在LLVM 3.1+和GCC 4.8+中
2.2ASAN能做什么
ASan可以检测出程序中不合理的内存使用行为,主要包括以下行为
错误行为 | 简介 |
---|---|
global buffer overflow | 全局内存访问越界 |
heap buffer overflow | 堆内存越界 |
initialization order bugs | 全局变量初始顺序异常 全局变量初始化之间存在依赖,导致实际运行时因为初始化顺序问题导致初始值异常 |
memory leaks | 内存泄漏 在程序正常退出时输出报告 |
stack buffer overflow | 栈内存访问越界 |
use after free | 访问已经释放的内存,在释放内存后仍然尝试访问此内存 |
use after return | 访问生命周期结束的对象在函数退出后尝试访问函数内声明的局部变量 |
2.3ASAN怎么做的
- 在编译时, ASan会替换malloc/free接口
- 在程序申请内存时, ASan会额外分配一部分内存来标识该内存的状态
- 在程序使用内存时, ASan会额外进行判断,确认该内存是否可以被访问,并在访问异常时输出错误信息
- 详细的工作原理有兴趣可以参考官方文档:https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm
2.4 如何使用
2.4.1 安装
- centos下使用:
yum install libasan -y
- 2,需要llvm-symbolizer做符号解析,否则输入错误信息只有地址信息没有符号信息: yum install -y Ilvm,检查时候which llvm
2.4.2 编译设置
编译选项
在CMakeList.txt中添加如下编译选项
add_compile_options(-00 -ggdb -std=c++14 -Wall -Wextra -mavx2
-fsanitize=address
-fno-omit-frame-pdinter
-fno-optimize-sibling-calls
-fsanitize-address-use-after-scope
-fsanitize-recover=address)
链接选项设置
add_link_options(-fsanitize=address)
环境变量
2.5注意事项
- asan版本程序在Linux环境下运行时会额外申请20TB的虚拟内存
- 需要确保/proc/sys/vm/overcommit_memory的值不为2
- 这也可以作为检验ASan是否工作的标志
- asan版本性能大幅受损,大约会下降2x左右
- asan工具不是万能的,他必须要跑到有问题的代码才可以暴漏出来
案例
https://blog.csdn.net/qq_37037348/article/details/130874941
命令
g++ -fsanitize=address -o test_asan test.cpp -g
-g 选项,加入调试信息,方便定位出错位置
代码
#include<iostream>
#include<stdlib.h>
using namespace std;
void func(){
int *x=(int *)malloc( 10 * sizeof ( int ) );
x[10]=0;
}
int main(){
func();cout<<"done"<<endl;
return ;
}