大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全家桶1年46,售后保障稳定
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工具使用。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/219122.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...