写在前面:

如果你发现你的程序栈写漏了(发现一个值突然发生了你预想不到的变化, 比如int a = 5,然后cout的时候就成了55)。

如果你发现你的程序每天占用内存都变大一点。

如果你发现你的程序core dump了。

如果你发现。。。

除了性能问题,都可以先用asan跑一下,说不定能发现什么。

缺点:

会让程序变得很慢,导致可能有些线程竞争的地方被刚好掩盖掉了。

0. 功能:

  • Use after free (dangling pointer dereference)

  • Heap buffer overflow

  • Stack buffer overflow

  • Global buffer overflow

  • Use after return

  • Use after scope

  • Initialization order bugs

  • Memory leaks

注释:版本不同,可能功能有所不同。

1. 环境

1. centos 6或7

gcc 4.8.5 : 只有Asan,即只能检测内存越界。

gcc 4.9.2 : 有Asan和Lsan两种,可以用asan来做越界检测,用lsan做内存泄露检测。(建议使用, gcc的安装跟gcc4.8.5一样,详看tensorflow 配置centos6环境)

gcc 7.2 : Asan中集成了LSan。(建议使用, gcc的安装跟gcc4.8.5一样,详看tensorflow 配置centos6环境),意思就是只用asan就可以啦。

2. 编译选项

因为gcc 4.9.2版本最复杂,所以我们就按照4.9.2的来写,4.8.5的不会有内存检测,7.2的不用做lsan, 以下我们写个编译的例子,很简单。

g++ main.cpp -g -llsan -fsanitize=leak -o main 

1. 需要注意的是需要带-g选项,会加入一些调试信息到符号表以供输出使用,不带也可以,如果不带,可能看不到错在哪一行;

2. 需要动态链接库liblsan.so,这个动态链接库会替换掉malloc等系统函数,在自己的malloc中加上统计信息,以达到检测内存泄露的作用。需要注意的点是,我们的环境中可能会有多个gcc或者找不到dso的时候。那么我们可以使用g++ --print-file-name=libasan.so来找到系统的动态链接库(只能是系统的库),这条命令会告诉你so在哪,但在我们的环境中我遇到了一个比较坑爹的问题。就是so是有,但是so的大小仅为4,里面写着让重新下载so。

3. -fsanitize=,这个有好几种选项、

1. asan(内存检测),如标题;

2. ubsan(未定义行为检测), 有的时候debug的程序没问题,release的程序会奇奇怪怪的core dump掉,那么你需要做这个检测;

3. tsan(线程安全检测),如标题;tsan有一个点需要注意,因为大家代码跑通后一般不会用tsan做检测,再者tsan出来时间不长,一些老的库会有非常多的线程安全问题。再加上检测条件非常严格。所以,大型项目第一用tsan做检查的时候,可能每一行都会有线程安全问题。

4. leak(泄露检测),被1包括了。

4. 如果我们有多个libasan.so,我们需要跟-L/path/to/lib,这个大家都懂,就不再叙述了。

5. 如果提示请加载PRELOAD,那么请export LD_PRELOAD=或者export LD_PRELOAD=/path/to/liblsan.so/libasan.so

我们今天主要讲asan,如果对tsan有兴趣可以看下官网,或者这篇文章,自己给自己打个广告,哈哈。

3. 泄露检测

我们写如下代码:

#include <iostream>using namespace std;int main()
{int *p = new int(5);std::cout << *p << std::endl;return 0;
}

该代码只有new,但没有delete函数。当我们使用上述例子,编译:

./g++ main.cpp -g -llsan -fsanitize=leak

然后我们可能会得到编译错误的提示 lsan没有找到。可以使用print找到,如下:

./g++ --print-file-name=liblsan.so

加上-L即可。这时我们就编好了一个带内存泄漏检查的可执行文件,之后我们./a.out。

可能会出现提示:请配置LD_PRELOAD环境变量(7.2),或者直接core dump(4.9), 或者提示本该属于leak检查的内存映射段被其他dso占用了(4.9)。都需要配置正确的LD_PRELOAD环境变量。

我们用之前找到的liblsan,配置到LD_PRELOAD内,例如:

export LD_PRELOAD=/root/local/lib64/libasan.so

运行即可,如果还崩,那就大象zhaozheng09。

如上代码,我们可以得到结果:

=================================================================
==1712101==ERROR: LeakSanitizer: detected memory leaksDirect leak of 4 byte(s) in 1 object(s) allocated from:#0 0x7fd00aabac28 in operator new(unsigned long) ../../../../libsanitizer/lsan/lsan_interceptors.cc:161#1 0x4008a7 in main /root/local/bin/main.cpp:7#2 0x7fd009ee0504 in __libc_start_main (/lib64/libc.so.6+0x22504)SUMMARY: LeakSanitizer: 4 byte(s) leaked in 1 allocation(s).

第9行,是个总结,他会告诉你总共泄露了4bytes,这4bytes属于1次开辟的。

4-7行,我们这里只泄露了一次,如果多次的话会有多个4-7行,会告诉你那个线程开辟的空间,哪个线程释放的空间。并且打印出详细的开辟和释放的函数栈,当然我们注意第五行,我们用的malloc已经被替换成lsan下的malloc了。

第2行,错误类型。

4.越界检测

首先注明一点,不一定只有越界导致core dump了才会打错误报告,只要访问到了不合法的内存都会报错,比如申请了一个包涵四个int元素的数组,而我们访问/修改了这个数组的第五个元素。那么就会报错。

直接看代码吧,如下代码:

#include <iostream>
#include <stdint.h>using namespace std;int main()
{char p[5] = "";uint8_t tmp = 5;p[-1] = 7;cout << (void*)p << endl;cout << (void*)&tmp << endl;cout << (uint32_t)tmp << endl;return 0;
}

编译代码:

g++ main.cpp -lasan -fsanitize=address -g

得到了a.out,然后我们去./a.out。如果我们裸跑,那么我们很奇怪的发现tmp被修改成了7。其实我就想描述一下,别的线程或者一不小心的越界都会导致各种奇奇怪怪的错误。这个时候,我们用上述命令编译之后。就会报告如下错误。

其实我觉得可能误报,因为这是一个在c++看来是允许的操作。但只是我们看起来用法不对而已。(过于偏激,不认同请忽略)

=================================================================
==1729613==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7ffd1db351ef at pc 0x400c24 bp 0x7ffd1db351b0 sp 0x7ffd1db351a8
WRITE of size 1 at 0x7ffd1db351ef thread T0#0 0x400c23 in main /root/code/test/asan/main.cpp:10#1 0x7fc9489b4504 in __libc_start_main (/lib64/libc.so.6+0x22504)#2 0x400a98 (/root/code/test/asan/main+0x400a98)Address 0x7ffd1db351ef is located in stack of thread T0 at offset 31 in frame#0 0x400b75 in main /root/code/test/asan/main.cpp:7This frame has 1 object(s):[32, 37) 'p' <== Memory access at offset 31 underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-underflow /root/code/test/asan/main.cpp:10 main
Shadow bytes around the buggy address:0x100023b5e9e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x100023b5e9f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x100023b5ea00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x100023b5ea10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x100023b5ea20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100023b5ea30: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1[f1]05 f40x100023b5ea40: f4 f4 f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 000x100023b5ea50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x100023b5ea60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x100023b5ea70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x100023b5ea80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):Addressable:           00Partially addressable: 01 02 03 04 05 06 07Heap left redzone:       faHeap right redzone:      fbFreed heap region:       fdStack left redzone:      f1Stack mid redzone:       f2Stack right redzone:     f3Stack partial redzone:   f4Stack after return:      f5Stack use after scope:   f8Global redzone:          f9Global init order:       f6Poisoned by user:        f7Contiguous container OOB:fcASan internal:           fe
==1729613==ABORTING

我们来分析一下结果。

第二行报出了错误类型。stack-buffer-underflow,并报出了sp,pc,bp寄存器里存放的值。

第三行报出操作WRITE,写了多少字节,且操作的线程是T0

第4-6行是T0的函数栈。

第八行表示那个地址出错,这个地址是属于谁,谁开辟的。

剩下的行表示出错误细节以及出错虚拟内存的情况,下面有有F1, F2等注解,可以详细看说明,我们这里表示错在了那个位置,覆盖了那个不该覆盖的变量。

我们只需要看函数栈就可以。

5. ASAN_OPTIONS/UBSAN_OPTIONS/LSAN_OPTIONS/TSAN_OPTIONS

下面的不用看了。上面的一般就够了,我也没用过,如果写错了,不用大象我。

asan设置了ASAN_OPTIONS环境变量,可以带更个性化的参数,比如可以选择是否出现内存泄露立刻停止,或者正常跑完后停止,或者不检测哪些文件的内存泄露,等等;但不知道我们的gcc4.8,4.9是不是支持属性。

详细内容请看上述官方文档。

一般除了使用tsan之外,不需要设置OPTIONS变量。

6.加入TensorFlow

1. 尽量将gcc版本更新到最高。

2. 在bazel的编译选项中加入-g -llsan -fsanitize=leak或-g -lasan -fsanitize=address。

3. 如果找不到leak,那么请设置CC和CXX环境变量。编译即可。

4. 如果让配置LD_PRELOAD,那么export LD_PRELOAD=即可。或者指向相应的dso。

5.注意:在使用asan和lsan的时候,我发现Python本身会报一些内存泄露或者误报,我们都不需要管,只要在里面没有出现我们自己写的代码的内存泄露或者越界错误即可。

6. ubsan可以正常使用,但是tsan遇到了conflict shadow memory的问题,让加-FPIC,加入后遇到编译错误。估计是一些.cc不支持固定地址。

c++ Asan(address-sanitize)的配置和使用相关推荐

  1. ISCW实验:配置Cisco IOS EASY ××× Server和Cisco ××× Client

    试验说明:R1为SKY公司的网关,其F1/0接口连接互联网,用户现在出差在外,通过拨号连接到互联网上,现在希望实现用户通过internet拨号进入SKY公司的R1路由器上,拨号使用easy ***,并 ...

  2. Ubuntu上nfs的安装配置

    Ubuntu上nfs的安装配置 2007-07-01 09:04 Ubuntu 默认是没有nfs服务的,所以需要自己安装 1.安装nfs服务版            apt-get install n ...

  3. cisco3550交换机配置手册

    cisco3550交换机配置手册 说明 本手册只包括日常使用的有关命令及特性,其它未涉及的命令及特性请参考英文的详细配置手册. 产品特性 3550EMI是支持二层.三层功能(EMI)的交换机 支持VL ...

  4. Catalyst3550交换机配置三层接口

    带有EMI的Catalyst3550交换机支持三种路由或桥接的三层接口: SVIs:你应该为任何你想路由流量的Vlan配置SVIs.当你在interface vlan全局配置命令后输入一个Vlan I ...

  5. Cisco路由器配置命令之模式转换命令

    Cisco路由器配置命令之配置命令 show running config 显示所有的配置 show versin 显示版本号和寄存器值 shut down 关闭接口 no shutdown 打开接口 ...

  6. 华为服务器参数配置文件,最实用的华为配置基础手册.doc

    经过Console 口登录 应用环境 用户需要经过Console 口登录到S-switch,图1-1 所表示. 图1-1 经过Console 口登录到S-switch 说明 假如S-switch 是第 ...

  7. Dubbo(八)使用配置类方式实现服务提供者消费者dubbo配置

    本文章基于改dubbo系列前两篇文章中项目进行调整修改 Dubbo(六)使用SpringBoot搭建dubbo服务提供者工程 Dubbo(七)使用SpringBoot搭建dubbo消费者工程 主要调整 ...

  8. 路由器IP-4-DUPADDR: Duplicate address和CDP-4-DUPLEX_MISMATCH错误的解决方案

    1. IP-4-DUPADDR: Duplicate address 现象:配置了路由器之后,console上不停地报IP-4-DUPADDR: Duplicate address错误 故障分析: 1 ...

  9. ASA 5505 配置

    asa 5505 1.配置防火墙名 ciscoasa> enable ciscoasa# configure terminal ciscoasa(config)# hostname asa550 ...

  10. 烽火2640路由器命令行手册-04-网络协议配置命令

    网络协议配置命令 目  录 第1章 IP寻址配置命令... 1 1.1 IP寻址配置命令... 1 1.1.1 arp. 1 1.1.2 arp timeout 2 1.1.3 clear arp-c ...

最新文章

  1. 3ds Max中的V-Ray学习
  2. [NOI2005]维护数列
  3. mysql 怎么查询结果补0_mysql查询连续时间数据——无数据补0
  4. c语言ffffff错误,C语言打印16进制出现0xffffff现象的问题剖析!
  5. BDB (Berkeley DB)简要数据库(转载)
  6. php+ksort+返回true,PHP preg_replace函数
  7. Android系统(116)---APP启动过程
  8. 华为 该软件被检测为风险软件_美团被华为标记为“病毒软件”,用户表示懵了,华为官方出面解释...
  9. linux opendir php,php目录遍历函数opendir用法实例
  10. Cadence Allegro PCB设计准备工作图文教程【入门篇1-3】
  11. 图神经网络的困境,用微分几何和代数拓扑解决
  12. 符号---Alt+数字键
  13. CSS常用的选择器学习
  14. man查询括号中的数字含义
  15. Linux系统下运行QT视频播放器示例程序(Media Player Example )
  16. 【转】博弈论中的几个经典问题
  17. 立足信息时代起点 探索企业营销新模式
  18. 雷军:技术立业 金山要向Google学习
  19. 博文第二天,一切刚刚开始
  20. 如何反击职场PUA?

热门文章

  1. 登月源码开源登顶GitHub No.1!接而又被中国程序员“玩坏”了
  2. c/c++: error: expected declaration or statement at end of input
  3. VUE中IE浏览器下载文件的解决方案
  4. 【Bluetooth|蓝牙开发】三、一篇文章,带你总览蓝牙协议
  5. 1063 计算谱半径
  6. Android-adb命令大全
  7. 第021篇:易康(eCognition)中用点矢量文件制作样本验证分类精度的操作方法
  8. 【github action+python】完成定时任务并推送(学会自制)
  9. 通过LRC文件分析出一首歌曲的速度
  10. Spring MVC之@RequestBody, @ResponseBody 详解