一、简介
sanitizers 是谷歌提供的一套开源工具,能够发现堆栈读写溢出、内存泄漏、线程数据竞争和死锁等问题。包括:
-
AddressSanitizers (Asan):检测地址相关问题,如use-after-free,heap-buffer-overflow, stack_buffer_overflow,use_after_return, memory_leak等。编译选项:-fsanitize=address
-
LeakSanitizers (Lsan):检测内存泄漏。编译选项:-fsanitize=leak,gcc7以上已包含到-fsanitize=address中.
-
ThreadSanitizers (Tsan):检测数据竞争和死锁。编译选项:-fsanitize=thread, 不能与-fsanitize=address一起打开
-
MemorySanitizer: gcc不支持,暂时不管。
-
UndefinedBehaviorSanitizer (UBSan): 检测未定义行为。编译选项:-fsanitize=undefined
这些工具能帮助我们提前发现很多问题,保证代码鲁棒性。 注意:工具未发现问题不代表代码100%安全。
二、使用方式(以centos为例)
由于-fsanitize=thread, 不能与-fsanitize=address同时开启。所以完成代码检测需分别编译运行两次。
2.1 下载sanitizers相关库
如果当前环境gcc是通过下面的方式下载安装的:
yum install centos-release-scl -y
yum install devtoolset-7-gcc* -y
scl enable devtoolset-7 bash
那么需要安装对应的库,命令如下:
yum install devtoolset-7-libasan-devel
yum install devtoolset-7-liblsan-devel
yum install devtoolset-7-libtsan-devel
yum install devtoolset-7-libubsan-devel 中间的数字7对应gcc的版本。
如果gcc是通过源码包编译安装的,那么sanitizers的这些库默认被安装了,不用再额外下载。
2.2 使用Asan、Lsan、UBsan
CMakeLists.txt 加上: set(CMAKE_CXX_FLAGS "-fsanitize=address -fno-omit-frame-pointer -g -fsanitize=undefined")
,并且设置CMAKE_BUILD_TYPE
为 Debug
( Release 会默认加上-O3编译选项,会优化掉一些代码,可能导致一些错误检测不到) 。编译demo和算法库,然后运行即可。下面是笔者使用asan排查出代码泄漏问题和crash问题的报错截图:
2.2.1 mem leak
Sanitizers 会在程序退出时(如main函数结束时),打印出泄漏的大小和位置。因为只有我们自己的库增加了相关的编译选项,所有能显示出泄漏位置,其他三方库就只有泄漏的位置偏移.
2.2.2 segmentation fault
如果没有使用asan,出现的segmentation fault的堆栈是在curl 内部函数中,排查该问题就非常棘手:
使用asan后的打印信息:
明确显示是写越界,而且指出了写越界时的代码位置以及该内存分配时的代码位置,排查是写内存时的size问题还是内存分配时size问题即可。
2.3 使用Tsan
CMakeLists.txt 加上: set(CMAKE_CXX_FLAGS " -fno-omit-frame-pointer -g -fsanitize=thread")
,并且设置CMAKE_BUILD_TYPE
为 Debug
.(Release 会默认加上-O3编译选项,会优化掉一些代码)。编译demo和算法库,然后运行即可。
示例代码:
#include <thread>
#include <iostream>
#include <stdio.h>
using namespace std;
void test1(int& date){
for(int i = 0; i < 5; i++){
date++;
}
std::cout<<"test1"<<std::endl;
}
void test2(int& date){
for(int i = 0; i < 5; i++){
date++;
}
std::cout<<"test2"<< std::endl;
}
int main(){
int a=0;
std::thread thread1(test1, std::ref(a));
std::thread thread2(test2, std::ref(a));
thread1.join();
thread2.join();
return 0;
}
报错截图:
三 功能简介
官方文档对每个点都有很详细的demo,可针对参考。
-
Use after free (dangling pointer dereference)
-
Heap buffer overflow
-
Stack buffer overflow
-
Global buffer overflow
-
Use after return Asan默认不会进行use-after-return 检测,需要设置ASAN_OPTIONS=detect_stack_use_after_return=1
-
Use after scope
-
Initialization order bugs
-
Memory leaks
-
UBSan