Linux问题调试(2)--内存问题与asan工具

一、问题

Linux项目开发过程中,时常会出现内存泄漏的问题,而这类问题却很难定位和排查,本文介绍一种定位内存泄漏问题的常用工具asan工具。

二、asan工具原理

asan全称AddressSanitizer,是一种面向c/c++语言的内存错误问题检查工具,目的是帮助开发者检测和调试内存相关的问题。gcc工具在4.8版本后加入了asan工具,但完整的asan功能需要在4.9.2以上才的以提供。

asan主要包括三个部分:

1、阴影内存shadow memory:ASAN算法的基石,占用一部分的内存区域,用于记录哪些内存地址是可以安全访问的,哪些内存地址是不可以访问的。

2、检测模块instrumentation module:编译期间,对代码进行修改,主要增加了以下两个内容:

1)在每一次内存访问前,先检查对应的内存地址的shadow状态,确定可以安全访问时才访问,否则报错。

2)在应用数据的前后增加毒区(poisoned redzones),毒区设置为不可寻址,用于检测stack和global objects类型的越界访问的错误。

3、运行时库run-time library:运行期间,对代码进行修改,主要是修改了malloc和free函数的实现方法,在heap上分配内存时,在应用数据前后创建毒区(poisoned redzones),用于检测heap类型的越界访问的错误。

asan算法的思想是:如果想防住Buffer Overflow泄漏,只需要在每块内存区域右端(或两端,能防overflow和underflow)加一块区域(RedZone),使RedZone的区域的影子内存(Shadow Memory)设置为不可写,如图1所示。

图1 asan工具映射关系图

这里举一个stack的例子,fun的原始代码,在栈上分配8个byte的内存空间:

void fun() {

  char a[8];

  ...

  return;

}

那么asan重构Shadow Memory检测stack的越界访问后,代码变化如下。 首先asan会在应用数据的前后增设大小为32byte的redzones,然后再给对应的Shadow地址赋值。可以看到,每8byte的redzones对应的1byte的Shadow的值都为0xff,是负数-1,代表全部8byte都不可寻址。

void fun() {

  char redzone1[32];  // 32-byte aligned

  char a[8];          // 32-byte aligned

  char redzone2[24];

  char redzone3[32];  // 32-byte aligned

  int  *shadow_base = MemToShadow(redzone1);

  shadow_base[0] = 0xffffffff;  // poison redzone1

  shadow_base[1] = 0xffffff00;  // poison redzone2, unpoison 'a'

  shadow_base[2] = 0xffffffff;  // poison redzone3

  ...

  shadow_base[0] = shadow_base[1] = shadow_base[2] = 0; // unpoison all

  return;

}

三、asan工具使用

1、查找编译链中的asan库,并将动态库移到项目中;

root&user:which arm-linux-gnueabihf-gcc

/opt/arm/arm-linux-gnueabihf-6.5/bin/arm-ca9-linux-gnueabihf-gcc

root&user: find /opt/arm/arm-linux-gnueabihf-6.5/ -name "*asan*"                               

/opt/arm/arm-linux-gnueabihf-6.5/lib/gcc/arm-linux-gnueabihf/6.5.0/include/sanitizer/asan_interface.h

/opt/arm/arm-linux-gnueabihf-6.5/lib/gcc/arm-linux-gnueabihf/6.5.0/plugin/include/asan.h

/opt/arm/arm-linux-gnueabihf-6.5/arm-linux-gnueabihf/lib/libasan.so.3.0.0

/opt/arm/arm-linux-gnueabihf-6.5/arm-linux-gnueabihf/lib/libasan.la

/opt/arm/arm-linux-gnueabihf-6.5/arm-linux-gnueabihf/lib/libasan.a

/opt/arm/arm-linux-gnueabihf-6.5/arm-linux-gnueabihf/lib/libasan.so

/opt/arm/arm-linux-gnueabihf-6.5/arm-linux-gnueabihf/lib/libasan_preinit.o

/opt/arm/arm-linux-gnueabihf-6.5/arm-linux-gnueabihf/lib/libasan.so.3

2、使用编译选项,编译可执行文件,生成可执行文件、可执行文件的map。

CFLAGS += -fsanitize=address -fsanitize-recover=address -fno-stack-protector  -fno-omit-frame-pointer

LDFLAGS += -l:libasan.a  //添加了动态库则不需要链接

-fsanitize=address:开启内存越界检测

-fsanitize-recover=address:一般后台程序为保持稳定性,不能遇到错误就简单退出,而是继续运行,采用该选项支持内存出错后程序继续运行,需要叠加设置环境变量ASAN_OPTIONS=halt_on_error才能生效;若不设置,则内存出错即报错退出

-fno-stack-protector:去使能栈溢出保护

-fno-omit-frame-pointer:检测到内存错误时,打印出函数调用栈

3、配置环境变量export,执行hicore

ASAN_OPTIONS=halt_on_error=0:malloc_context_size=10:quarantine_size_mb=0:log_path=/home/asan.log

四、asan信息解读

==3322==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61400000ffd0

at pc 0x0000004008e0 bp 0x7ffeddce53a0 sp 0x7ffeddce5390

READ of size 4 at 0x61400000ffd0 thread T0

#0 0x4008df in main /home/heap_buf_overflow.cpp:5

#1 0x7f3b83d0882f in __libc_start_main (/lib/x86_64-linuxgnu/libc.so.6+0x2082f)

#2 0x4007b8 in _start (/home/build/heap_buf_overflow+0x4007b8)



0x61400000ffd0 is located 0 bytes to the right of 400-byte region [0x61400000fe40,0x61400000ffd0) allocated by thread T0 here:

#0 0x7f3b841516b2 in operator new[](unsigned long) (/usr/lib/x86_64-linuxgnu/libasan.so.2+0x996b2)

#1 0x40089e in main /home/heap_buf_overflow.cpp:4

#2 0x7f3b83d0882f in __libc_start_main (/lib/x86_64-linuxgnu/libc.so.6+0x2082f)



SUMMARY: AddressSanitizer: heap-buffer-overflow /home/heap_buf_overflow.cpp:5 main

第一部分(ERROR):指出错误类型是heap-use-after-free,asan可以检测的内存问题如下。

​
heap-buffer-overflow         //堆缓冲区溢出

stack-buffer-overflow         //栈缓冲区溢出

global-buffer-overflow       //全局变量溢出

heap-use-after-free          //使用悬空指针(指针已经释放,却使用了)

stack-use-after-scope        //使用退出作用域的内存,野指针

attempting double-free       //重复释放

initialization-order-fiasco   //初始化顺序问题

Detected memory leaks        //内存泄漏
​

第二部分(READ):指出线程名thread T0,操作为READ,发生的位置是use-after-free.c:5。 该heap块之前已经在use-after-free.c:4被释放了。

第三部分 (SUMMARY) 前面输出的概要说明。

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值