sanitizer工具集的介绍

Sanitizers是谷歌发起的开源工具集,包括了Address Sanitizer, undefined behavior Sanitizer, Thread Sanitizer, Leak Sanitizer。GCC从4.8版本开始支持Address sanitizer和Thread Sanitizer,4.9版本开始支持Leak Sanitizer和undefined behavior Sanitizer。

Address Sanitizer(ASAN):

也即地址消毒技术,通过编译插桩(CTI),能够发现此堆/栈/全局变量读写溢出,内存泄露等问题,并将信息直接打印到日志中。Address Sanitizer(ASan)是一个快速的内存错误检测工具。它非常快,只拖慢程序两倍左右(比起Valgrind快多了)。它包括一个编译器instrumentation模块和一个提供malloc()/free()替代项的运行时库。

Thread Sanitizer(TSan):

是一个检查线程Data Race的C/C++工具。

Leak Sanitizer(LSan):

检测内存的LeakSanitizer是集成在Address Sanitizer中的一个相对独立的工具,它工作在检查过程的最后阶段。

Undefiend Behavior Sanitizer(UBSan):

检测未定义行为(使用空指针、有符号整数溢出等)。

环境配置

QMake:

在pro文件中添加:

QMAKE_CXXFLAGS+="-fsanitize=undefined,address,leak -fno-omit-frame-pointer"
QMAKE_CFLAGS+="-fsanitize=undefined,address,leak -fno-omit-frame-pointer"
QMAKE_LFLAGS+="-fsanitize=undefined,address,leak -fno-omit-frame-pointer"

用-fsanitize=address选项,编译和链接你的程序。
用undefined,可以使用undefined behavior sanitizer检测未定义行为。
用leak,可以使用leak sanitizer检测内存泄露(很多平台默认关闭,x86架构下默认开启的)。
用-fno-omit-frame-pointer(与相对)编译,以得到更容易理解stack trace。
注:-fomit-frame-pointer是打开优化选项(-O1打开),与-fno-omit-frame-pointer相反,即在函数调用时不保存栈帧指针SFP,代价是不能通过backtrace进行调试根据堆栈信息了。

TSan环境配置:
主要用于检测多线程资源竞争的问题,但是该选项不能与-fsanitize=address、-fsanitize=leak组合。
在pro文件中添加:

QMAKE_CXXFLAGS+="-fsanitize=thread"<br>
QMAKE_CFLAGS+="-fsanitize=thread"<br>
QMAKE_LFLAGS+="-fsanitize=thread"<br>

CMake

在CMakeLists添加:

set(CMAKE_CXX_FLAGS "-fsanitize=undefined,address,leak -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS "-fsanitize=undefined,address,leak -fno-omit-frame-pointer")
set(CMAKE_L_FLAGS "-fsanitize=undefined,address,leak -fno-omit-frame-pointer")

TSan环境配置:

set(CMAKE_CXX_FLAGS "-fsanitize=thread")
set(CMAKE_C_FLAGS "-fsanitize=thread")
set(CMAKE_L_FLAGS "-fsanitize=thread")

工作原理和使用方法

原理

Address Sanitizer替换了malloc和free的实现。当调用malloc函数时,它将分配指定大小的内存A,并将内存A周围的区域标记为”off-limits“。当free方法被调用时,内存A也被标记为”off-limits“,同时内存A被添加到隔离队列,这个操作将导致内存A无法再被重新malloc使用。
  当访问到被标记为”off-limits“的内存时,Address Sanitizer就会报告异常。
  
=== 错误类型 ===

  • Use after free  释放后使用
  • Heap buffer overflow 堆缓冲区溢出
  • Stack buffer overflow 栈缓冲区溢出
  • Global buffer overflow 全局缓冲区溢出
  • Use after return 返回后使用
  • Use after scope 作用域后使用
  • Initialization order bugs 初始化顺序错误
  • Memory leaks 内存泄露
  • Using misaligned or null pointer  使用未对齐的指针
  • Signed integer overflow  有符号整数溢出
  • Conversion to, from, or between floating-point types which would overflow the destination  和浮点数相关转换溢出
  • data race  数据竞争

错误示例:

==== Address Sanitizer ====

int main()   {int* array = new int[100];delete [] array;return array[1];
}

====16829 ====
ERROR: AddressSanitizer: heap-use-after-free on address 0x614000000044 at pc 0x00000065b3ea bp 0x7fffffffe3a0 sp
0x7fffffffe398
· 第一部分(ERROR)指出错误类型是heap-use-after-free; READ of
size 4 at 0x614000000044 thread T0
#0 0x65b3e9 in main …/…/deepin-image-viewer/viewer/main.cpp:33
#1 0x7ffff4b2409a in __libc_start_main …/csu/libc-start.c:308
#2 0x440319 in _start (/data/home/shuwenzhi/workspace/sp2/build-deepin-image-viewer-unknown-Debug/viewer/deepin-image-viewer+0x440319)
· 第二部分(READ), 指出线程名thread T0,操作为READ,发生的位置是main.cpp:33。
libc_start_main()函数应执行执行环境的任何必要初始化,使用适当的参数调用main函数,并处理main()的返回。
0x614000000044 is located 4 bytes inside of 400-byte region
[0x614000000040,0x6140000001d0) freed by thread T0 here:
#0 0x7ffff72f3c40 in operator delete (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xebc40)
#1 0x65b3ab in main …/…/deepin-image-viewer/viewer/main.cpp:32
#2 0x7ffff4b2409a in __libc_start_main …/csu/libc-start.c:308 · 第二部分(freed), 该heap块之前已经在main.cpp:32被释放了; previously allocated by
thread T0 here:
#0 0x7ffff72f2ef0 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xeaef0)
#1 0x65b38b in main …/…/deepin-image-viewer/viewer/main.cpp:31
#2 0x7ffff4b2409a in __libc_start_main …/csu/libc-start.c:308 · 第二部分(allocated), 该heap块是在main.cpp:31分配。 SUMMARY: AddressSanitizer:
heap-use-after-free …/…/deepin-image-viewer/viewer/main.cpp:33 in
main · 第三部分 (SUMMARY) 前面输出的概要说明。

==== Undefined Behavior Sanitizer ====

void testsignoverflow()  {int k = 0x7fffffff;k += 2;
}

…/worktest/testaddress/main.cpp:11:7: runtime error: signed integer overflow: 2147483647 + 2 cannot be represented in type ‘int’ ·
超过int范围,不能用int表达。

==== Leak Sanitizer ====

void* p;
int main(){p = malloc(4);p = 0;return 0;
}

==7089 == ERROR: LeakSanitizer: detected memory leaks 错误类型:detected memory leaks。 Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x7f13b7aab330 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xe9330)
#1 0x65b36b in main …/…/deepin-image-viewer/viewer/main.cpp:33
#2 0x7f13b52de09a in __libc_start_main …/csu/libc-start.c:308 内存在main.cpp:33分配。 SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1
allocation(s)。

==== Thread Sanitizer ====

int Global;
void *Thread1(void *x) {Global++;return NULL;
}
void *Thread2(void *x) {Global--;return NULL;
}
int main(){pthread_t t[2];pthread_create(&t[0], NULL, Thread1, NULL);pthread_create(&t[1], NULL, Thread2, NULL);pthread_join(t[0], NULL);pthread_join(t[1], NULL);
}

WARNING: ThreadSanitizer: data race (pid=26333)
· 错误类型:data
race
Read of size 4 at 0x000000408174 by thread T2:
#0
Thread2(void*) …/worktest/testaddress/main.cpp:47
(testaddress+0x403520)
#1 (libtsan.so.0+0x29b3d)

· 在线程T2读取4个字节,发生在main.cpp:47。
Previous write of size 4 at
0x000000408174 by thread T1:
#0 Thread1(void*)
…/worktest/testaddress/main.cpp:42 (testaddress+0x4034db)
#1
(libtsan.so.0+0x29b3d)
·
在线程T1读取4个字节,发生在main.cpp:42。
Location is global ‘Global’ of size 4
at 0x000000408174 (testaddress+0x000000408174)
Thread T2
(tid=26336, running) created by main thread at:
#0 pthread_create
(libtsan.so.0+0x2be1b)
#1 main
…/worktest/testaddress/main.cpp:74 (testaddress+0x403672)
Thread
T1 (tid=26335, finished) created by main thread at:
#0
pthread_create (libtsan.so.0+0x2be1b)
#1 main
…/worktest/testaddress/main.cpp:73 (testaddress+0x403651)

SUMMARY: ThreadSanitizer: data race
…/worktest/testaddress/main.cpp:47 in Thread2(void*)
·
线程T1、T2在主线程main.cpp的73和74行创建。

=== 使用建议 ===
ASAN、LSan、UBSan:
对可能出现内存泄露、访问越界、堆栈溢出,可以使用此三种工具同时检查,建议在每次提交代码之前,开启此三项检查,可以排除大部分常见错误,项目不大的话也可以配置到debug里。
Thread Sanitizer(TSan):
由于此工具会和其他工具组合冲突,建议在新增线程或者线程中可能出现data trace的情况下使用。例如:出现多线程的线程安全问题,可以开启此工具检查。
错误输出:
在正常的项目开发中,会有存有大量的日志信息输出到应用程序输出里,这样会加大查找错误信息的难度,因此建议在将sanitizer错误信息输出到日志里。

#include <sanitizer/asan_interface.h>
__sanitizer_set_report_path("asan.log")

在指定的目录会生成一个asan.log.pid(进程号)的文件。

总结

环境兼容

  • x86:可以正常使用。
  • 盘古V(wayland):错误信息不在应用程序输出里,而在编译输出里,有一个问题,编译输出错误信息后将错误代码删除,重新编译仍有错误信息。
  • 鲲鹏(arm):可以正常使用,与x86使用相同。
  • 龙芯(MIPS):不支持MIPS,缺少对应环境。

使用人员

  • 研发人员:由于使用sanitizer工具集需要代码编译,因此建议研发人员使用。
  • 测试人员:使用建议使用valgrind,详细使用请参照valgrind工具使用。

sanitizer工具集相关推荐

  1. gcc自带sanitizer工具使用

    Sanitizers是谷歌发起的开源工具集,包括了AddressSanitizer, MemorySanitizer, ThreadSanitizer, LeakSanitizer,Sanitizer ...

  2. blktrace 工具集使用 及其实现原理

    文章目录 工具使用 原理分析 内核I/O栈 blktrace 代码做的事情 内核调用 ioctl 做的事情 BLKTRACESETUP BLKTRACESTOP BLKTRACETEARDOWN 内核 ...

  3. binutils工具集用法

    addr2line用于得到程序指令地址所对应的函数,以及函数所在的源文件名和行号. 在不少嵌入式开发环境中,编译器的名称往往不是gcc,而是想arm-rtems-gcc这样的,对于这种命名形式的编译器 ...

  4. 【linux】Valgrind工具集详解(八):Memcheck命令行参数详解

    [linux]Valgrind工具集详解(五):命令行详解中不够全,在此专门针对Memcheck工具中的命令行参数做一次详细的解释. Memcheck命令行选项 –leak-check=<no| ...

  5. 【linux】Valgrind工具集详解(五):命令行详解

    一.使用方法 usage: valgrind [options] prog-and-args 使用方法:valgrind [参数选项] 程序和参数 二.选择工具 tool-selection opti ...

  6. 【linux】Valgrind工具集详解(一):简介

    一.Valgrind概述 Valgrind是用于构建动态分析工具的仪器框架.它附带了一组工具,每个工具都执行某种调试,分析或类似任务,可帮助您改进程序.Valgrind的架构采用模块化设计,因此可以轻 ...

  7. (翻译)LearnVSXNow! #6 - 创建我们第一个工具集 - 序幕

    在前面的文章中,我们在向导的帮助下创建了一些小的VSPackages.在第五讲中我们整理了VSX的一些思路和概念,深入VSPackages 了解了packages如何工作以及服务的机制.在这篇文章中我 ...

  8. 亚马逊云科技在中国区域上线机器学习新服务,打造广泛而深入的人工智能与机器学习工具集

    2021年5月11日,在完全托管的机器学习服务Amazon SageMaker落地中国区域一周年之际,亚马逊云科技宣布通过与光环新网和西云数据的紧密合作在中国区域进一步落地多项人工智能与机器学习的新服 ...

  9. 暗渡陈仓:用低消耗设备进行破解和渗透测试1.2.2 渗透测试工具集

    1.2.2 渗透测试工具集 Deck包含大量的渗透测试工具.设计理念是每个可能会用到的工具都应该包含进来,以确保在使用时无须下载额外的软件包.在渗透测试行动中给攻击机安装新的软件包很困难,轻则要费很大 ...

最新文章

  1. pandas 里面对nan的判断
  2. C#简单实现读取txt文本文件并分页存储到数组
  3. Python将数据插入到数据库时遇到单引号插入错误的问题
  4. spring boot 跨域请求_SpringBoot 系列教程 web 篇之自定义请求匹配条件 RequestCondition...
  5. Windows 11 小技巧- WSL运行本地GPU算力
  6. Safari浏览器不支持……
  7. python dir()函数使用
  8. mysql 执行计划 视频_MySQL执行计划的讲解
  9. sklearn中的train_test_split函数
  10. BTCU 分叉,真的是比特币“千年痛点”克星吗?
  11. linux嵌入式入门到精通视频教程 Linux开发工程师培训教程
  12. 为什么CSDN登陆是明文传输账户密码
  13. ggplot制作条形图
  14. 用python制作音乐_Python3使用PySynth制作音乐的方法
  15. 微信打飞机小游戏的尝试
  16. 智云大咖秀:怎样的稳定器才是摄影师的“灵魂辅助”?
  17. plus钱包受黑客攻击_如何保护您的在线业务免受黑客攻击
  18. windows+MAC系统使用-快捷键
  19. 5年Java开发月薪43k 谁能想到实习期的我月薪只有2K呢?
  20. es7版本数据备份与恢复(生产环境)

热门文章

  1. Jsdoc-to-markdown
  2. 实战-Android 认证Wifi 连接后自动弹出认证界面
  3. Java同一个线程对象能否多次调用start方法
  4. 平煤转债上市价格预测
  5. phonopy计算模式格林艾森常数
  6. 5.10中国品牌日,助力中国产品向中国品牌转变!
  7. 【Docker】在CentOS上安装Docker Engine
  8. 啃完阿里这份高并发编程核心笔记,反手涨了 5K
  9. thymeleaf中用ajax
  10. 跳过51单片机,直接学习STM32单片机怎么样?