内存泄漏检测工具Asan

目录

      • 一、版本及安装
      • 二、编译选项
      • 三、原理
      • 四、错误类型
      • 五、使用测试

ASAN,全称 AddressSanitizer,可以用来检测内存问题,例如缓冲区溢出或对悬空指针的非法访问等。
根据谷歌的工程师介绍 ASAN 已经在 chromium 项目上检测出了300多个潜在的未知bug,而且在使用 ASAN 作为内存错误检测工具对程序性能损耗也是及其可观的。
根据检测结果显示可能导致性能降低2倍左右,比Valgrind(官方给的数据大概是降低10-50倍)快了一个数量级。而且相比于Valgrind只能检查到堆内存的越界访问和悬空指针的访问,ASAN 不仅可以检测到堆内存的越界和悬空指针的访问,还能检测到栈和全局对象的越界访问。
这也是 ASAN 在众多内存检测工具的比较上出类拔萃的重要原因,基本上现在 C/C++ 项目都会使用ASAN来保证产品质量,尤其是大项目中更为需要。

一、版本及安装

链接出错:

$ gcc -g asan.c -fsanitize=address -fno-omit-frame-pointer
/usr/bin/ld: cannot find /usr/lib64/libasan.so.0.0.0
collect2: error: ld returned 1 exit status

gcc版本:

  • 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就可以啦。

CentOS 安装:

sudo yum install libasan

Ubuntu 安装:

sudo apt-get install libasan0

二、编译选项

sanitizers项目,包含了 ASAN、LSAN、MSAN、TSAN等内存、线程错误的检测工具。
可检测的问题:

  • 内存泄漏
  • 堆栈和全局内存越界访问
  • free后继续使用
  • 局部内存被外层使用
  • Initialization order bugs

工具分类:

  • ASAN: 内存错误检测工具,全称 AddressSanitizer,可以用来检测内存问题,例如缓冲区溢出或对悬空指针的非法访问等。在编译命令中添加-fsanitize=address启用

  • LSAN: 内存泄漏检测工具,已经集成到 ASAN 中,可以通过设置环境变量ASAN_OPTIONS=detect_leaks=0来关闭ASAN上的LSAN,也可以使用-fsanitize=leak编译选项代替-fsanitize=address来关闭ASAN的内存错误检测,只开启内存泄漏检查。

  • MSAN: 对程序中未初始化内存读取的检测工具,可以在编译命令中添加-fsanitize=memory -fPIE -pie启用,还可以添加-fsanitize-memory-track-origins选项来追溯到创建内存的位置

  • TSAN: 对线程间数据竞争的检测工具,在编译命令中添加-fsanitize=thread启用 其中ASAN就是我们今天要介绍的重头戏。

三、原理

github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm

四、错误类型

错误类型

  • (heap) use after free 释放后使用
  • heap buffer overflow 堆缓存访问溢出
  • stack buffer overflow 栈缓存访问溢出
  • global buffer overflow 全局缓冲访问溢出
  • use after return
  • use after scope
  • initializations order bugs
  • memory leaks 内存泄露 LeakSanitizer: detected memory leaks

五、使用测试

asan.c

#include 
#include 

int funtest(void)
{
        char *p = (char *)malloc(10);
        p[10] = 99;	//越界
        return 0;
}

int main(int argc, char *argv[])
{
        funtest();
        return 0;
}
  • 用-fsanitize=address选项编译和链接程序
  • 用-fno-omit-frame-pointer编译,以得到更容易理解stack trace

编译执行:

$ gcc -g asan.c -fsanitize=address -fno-omit-frame-pointer
$ ./a.out  
=================================================================
==11540== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60040000dffa at pc 0x4006ef bp 0x7ffea8345f70 sp 0x7ffea8345f60
WRITE of size 1 at 0x60040000dffa thread T0
    #0 0x4006ee (/home/test/asan/a.out+0x4006ee)
    #1 0x40070c (/home/test/asan/a.out+0x40070c)
    #2 0x7fb843b2c3d4 (/usr/lib64/libc-2.17.so+0x223d4)
    #3 0x4005d8 (/home/test/asan/a.out+0x4005d8)
0x60040000dffa is located 0 bytes to the right of 10-byte region [0x60040000dff0,0x60040000dffa)
allocated by thread T0 here:
    #0 0x7fb843eecef9 (/usr/lib64/libasan.so.0.0.0+0x15ef9)
    #1 0x4006ae (/home/test/asan/a.out+0x4006ae)
    #2 0x40070c (/home/test/asan/a.out+0x40070c)
    #3 0x7fb843b2c3d4 (/usr/lib64/libc-2.17.so+0x223d4)
Shadow bytes around the buggy address:
  0x0c00ffff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c00ffff9bf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa 00[02]
  0x0c00ffff9c00:fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c00ffff9c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==11540== ABORTING

你可能感兴趣的:(Linux系统调试,asan,linux,内存泄漏)