内存问题的排查工具和方法– Clang的AddressSanitizer

1 概述

Valgrind可以有效地监测处大多数内存问题,你肯定忍不住会想,既然c/c++的内存问题这么常见,为什么不在编译器中加入内存问题检测的功能呢? 很可惜,GCC中还目前还不支持内存检测,可喜的是,clang支持。这里我们看看如何用clang发现内存问题

2 clang

clang 是一个C、C++、Objective-C编程语言的编译器前端。它采用了底层虚拟机作为其后端。它的目标是提供一个GNU编译器套装(GCC)的替代品, 作者是克里斯·拉特纳,在苹果公司的赞助下进行开发。

3 内存泄漏监测

AddressSanitizer是clang中的一个内存错误检测器,它可以检测到以下问题:

  • Out-of-bounds accesses to heap, stack and globals
  • Use-after-free
  • Use-after-return (to some extent)
  • Double-free, invalid free
  • Memory leaks (experimental)

使用clang编译代码时用-fsanitize=address就能打开AddressSanitizer工具,为了在检测到内存错误时打印出您的程序调用栈,需要在编译时加上选项 -fno-omit-frame-pointer选项,同时为了得出更清晰的调用栈信息,请用-O1选项编译程序。

4 示例代码

下面我用clang3.4做一个示例

 1:  int main()
 2:  {
 3:      char *p = malloc(sizeof(char) * 10);
 4:      if (p == NULL) {
 5:          return 0;
 6:      }
 7:
 8:      struct elem *e = malloc(sizeof(struct elem));
 9:      if (e == NULL) {
10:          free(p);
11:          return 0;
12:      }
13:
14:      e->a = 10;
15:      e->b = 10.10;
16:      e->c = p;
17:
18:      double *xx = &e->b;
19:
20:      printf("%f\n", *xx);
21:
22:      free(e);
23:
24:      printf("%f\n", *xx);
25:
26:      return 0;
27:  }

上面的代码中有两处问题,一是p未被释放,导致了内存泄漏;二是xx指向了一块被释放了的内存。我们看看怎么用clang检测这两个问题

4.1 编译它

1:  clang -O1 -g -fsanitize=address -fno-omit-frame-pointer -o core core.c

4.2 用AddressSanitizer监测进程的内存泄漏

直接运行core文件,它就会自动打印出检测到的内存错误

 1:  [[email protected] test]$ ./core
 2:  10.100000
 3:  =================================================================
 4:  ==11254==ERROR: AddressSanitizer: heap-use-after-free on address 0x60300000efe8 at pc 0x48211a bp 0x7fff2c776450 sp 0x7fff2c776448
 5:  READ of size 8 at 0x60300000efe8 thread T0
 6:      #0 0x482119 in main /home/cobbliu/test/core.c:35
 7:      #1 0x36a101ecdc in __libc_start_main (/lib64/libc.so.6+0x36a101ecdc)
 8:      #2 0x481f3c in _start (/home/cobbliu/test/core+0x481f3c)
 9:
10:  0x60300000efe8 is located 8 bytes inside of 24-byte region [0x60300000efe0,0x60300000eff8)
11:  freed by thread T0 here:
12:      #0 0x46bca9 in __interceptor_free /home/ads/build23_6u0_x64/workspace/t-coresystem-clang/label/build23_6u0_x64/t-coresystem-clang/llvm-3.4/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:64
13:      #1 0x4820c0 in main /home/cobbliu/test/core.c:32
14:      #2 0x36a101ecdc in __libc_start_main (/lib64/libc.so.6+0x36a101ecdc)
15:
16:  previously allocated by thread T0 here:
17:      #0 0x46be29 in malloc /home/ads/build23_6u0_x64/workspace/t-coresystem-clang/label/build23_6u0_x64/t-coresystem-clang/llvm-3.4/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:74
18:      #1 0x48202a in main /home/cobbliu/test/core.c:18
19:      #2 0x36a101ecdc in __libc_start_main (/lib64/libc.so.6+0x36a101ecdc)
20:
21:  SUMMARY: AddressSanitizer: heap-use-after-free /home/cobbliu/test/core.c:35 main
22:  Shadow bytes around the buggy address:
23:    0x0c067fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
24:    0x0c067fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
25:    0x0c067fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
26:    0x0c067fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
27:    0x0c067fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
28:  =>0x0c067fff9df0: fa fa fa fa fa fa fa fa fa fa fa fa fd[fd]fd fa
29:    0x0c067fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
30:    0x0c067fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
31:    0x0c067fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
32:    0x0c067fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
33:    0x0c067fff9e40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
34:  Shadow byte legend (one shadow byte represents 8 application bytes):
35:    Addressable:           00
36:    Partially addressable: 01 02 03 04 05 06 07
37:    Heap left redzone:     fa
38:    Heap right redzone:    fb
39:    Freed heap region:     fd
40:    Stack left redzone:    f1
41:    Stack mid redzone:     f2
42:    Stack right redzone:   f3
43:    Stack partial redzone: f4
44:    Stack after return:    f5
45:    Stack use after scope: f8
46:    Global redzone:        f9
47:    Global init order:     f6
48:    Poisoned by user:      f7
49:    ASan internal:         fe
50:  ==11254==ABORTING

可以看到,程序在提示core.c的第35行有个heap-use-after-free的错误,而且在最后还有个summary,把出错的代码位置和相应的栈信息打了出来。

5 示例代码2

上面的代码做一些小修改,我们看看它对double-free问题的检测

1:  /...
2:      struct elem *e2 = e;
3:      free(e);
4:      free(e2);
5:  /...
6:  }

按照上面相同的方法编译并运行后,提示信息如下:

 1:  [[email protected] test]$ ./core
 2:  10.100000
 3:  =================================================================
 4:  ==11952==ERROR: AddressSanitizer: attempting double-free on 0x60300000efe0 in thread T0:
 5:      #0 0x46bca9 in __interceptor_free /home/ads/build23_6u0_x64/workspace/t-coresystem-clang/label/build23_6u0_x64/t-coresystem-clang/llvm-3.4/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:64
 6:      #1 0x4820bd in main /home/cobbliu/test/core.c:34
 7:      #2 0x36a101ecdc in __libc_start_main (/lib64/libc.so.6+0x36a101ecdc)
 8:      #3 0x481f3c in _start (/home/cobbliu/test/core+0x481f3c)
 9:
10:  0x60300000efe0 is located 0 bytes inside of 24-byte region [0x60300000efe0,0x60300000eff8)
11:  freed by thread T0 here:
12:      #0 0x46bca9 in __interceptor_free /home/ads/build23_6u0_x64/workspace/t-coresystem-clang/label/build23_6u0_x64/t-coresystem-clang/llvm-3.4/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:64
13:      #1 0x4820b0 in main /home/cobbliu/test/core.c:33
14:      #2 0x36a101ecdc in __libc_start_main (/lib64/libc.so.6+0x36a101ecdc)
15:
16:  previously allocated by thread T0 here:
17:      #0 0x46be29 in malloc /home/ads/build23_6u0_x64/workspace/t-coresystem-clang/label/build23_6u0_x64/t-coresystem-clang/llvm-3.4/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:74
18:      #1 0x482026 in main /home/cobbliu/test/core.c:18
19:      #2 0x36a101ecdc in __libc_start_main (/lib64/libc.so.6+0x36a101ecdc)
20:
21:  SUMMARY: AddressSanitizer: double-free /home/ads/build23_6u0_x64/workspace/t-coresystem-clang/label/build23_6u0_x64/t-coresystem-clang/llvm-3.4/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:64 __interceptor_free
22:  ==11952==ABORTING

可以看到,AddressSanitizer报错,说core.c的34行有一个double-free的错误

6 示例代码3

上面的代码做一些小修改,把释放e的代码注释掉,看看它对内存泄漏的检测

1:  /...
2:      //free(e);
3:  /...
4:  }

按照上面相同的方法编译并运行后,提示信息如下:

1:  [[email protected] test]$ ./core
2:  10.100000

可以看到,对内存泄漏,AddressSanitizer无法检测出来 clang中有一个工具叫LeakSanitizer,它的设计目标是用来检测内存泄漏。直到3.7版,LeakSanitizer也是在实验阶段。

7 AddressSanitizer的缺陷

  • AddressSanitizer工具编译的程序的堆栈和栈占用比原生程序的大。
  • AddressSanitizer不支持静态编译

Date: 2015-04-16T21:24+0800

Author: Cobbliu

Org version 7.9.3f with Emacs version 24

Validate XHTML 1.0

时间: 2024-07-31 12:28:57

内存问题的排查工具和方法– Clang的AddressSanitizer的相关文章

Windows系统中内存泄露与检测工具及方法

1.检测需要使用的工具:windbg工具.检测前,需要先安装windbg工具.安装了该工具后,会在安装目录下有一个umdh工具.假设windbg安装在以下目录下:D:\Program Files\Debugging Tools for Windows (x86) 2.内存泄露检测技巧2.1 运行cmd窗口,将路径设置到安装路径下:2.2 在该cmd窗口中设置环境变量_NT_SYMBOL_PATH:D:\Program Files\Debugging Tools for Windows (x86)

linux下常见内存异常查证工具和方法介绍

linux下常见内存异常查证工具和方法介绍 内存异常导致的异常往往很难查证,本文介绍在linux下的各种常见内存异常的查证工具和方法. 1.访问空指针/未初始化指针 这个是最简单的内存异常了,只要能够生成coredump文件,可以快速定位问题代码. 开启coredump 部分环境下默认不会生成coredump,需要运行如下命令:ulimit -c unlimited //unlimited表示不限制coredump文件大小,也可以指定一个最大文件大小. 定制core文件名 默认的coredump

内存问题排查工具 --- valgrind

1. 概述 2. Valgrind 3. 内存泄漏监测 3.1. 示例代码 3.2. 编译它 3.3. 用Valgrind监测进程的内存泄漏 4. 悬挂指针 4.1. 示例代码 4.2. Valgrind运行结果 5. 多次释放同一个指针 5.1. 示例代码 5.2. Valgrind 监测 6. Valgrind的优缺点 6.1. Advantages 6.2. Disadvantages 7. Valgrind的其他工具 7.1. Cachegrind 7.2. Callgrind 7.3.

详解Linux中的日志及用日志来排查错误的方法

这篇文章主要介绍了详解Linux中的日志及用日志来排查错误的方法,是Linux入门学习中的基础知识,需要的朋友可以参考下 Linux 系统日志许多有价值的日志文件都是由 Linux 自动地为你创建的.你可以在 /var/log 目录中找到它们.下面是在一个典型的 Ubuntu 系统中这个目录的样子: 一些最为重要的 Linux 系统日志包括: /var/log/syslog 或 /var/log/messages 存储所有的全局系统活动数据,包括开机信息.基于 Debian 的系统如 Ubunt

LeakCanary:简单粗暴的内存泄漏检測工具

差点儿每一个程序猿在开发的过程中都会遇到内存泄漏.那么我们怎样检測到app是否哪里出现内存泄漏呢?square公司推出了一款简单粗暴的检測内存泄漏的工具-- LeakCanary 什么是内存泄漏? 内存泄漏是指因为疏忽或者错误造成程序未能释放已经不再使用的内存,内存泄漏不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误失去了对于这段内存的控制.因而造成内存的浪费. 内存泄漏和内存溢出是两码事,不要混淆,内存溢出通俗的讲就是内存不够用,如今的仅仅能手机内存越来越大,内存溢出的情况不

页面静态化1---概念(Apache内置压力测试工具使用方法)

三个概念 ①静态网址: http://127.0.0.1/regis.html ②动态网址:在请求页面时可以动态的传一些值进去. http://127.0.0.1/regis.php?id=45&title=今天天气不错 ③伪静态网址: 伪静态仅仅是对动态网址的一个重写,伪静态网址不能让动态网址静态化,搜索引擎不会认为伪静态就是HTML文档,其次伪静态可取,但是应把重心放在取出冗余参数.规范URL,竟可能的避免重复也等等. 举例说明:http://v.youku.com/v_show/id_XM

内存泄漏以及常见的解决方法

  之所以撰写这篇文章是由于前段时间花费了非常大的精力在已经成熟的代码上再去处理memory leak问题.写此的目的是希望我们应该养成良好的编码习惯,尽可能的避免这种问题,由于当你对着一大片的代码再去处理此类的问题,此时无疑添加了解决的成本和难度.准确的说属于补救措施了. 1. 什么是内存泄漏(memory leak)?  指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内

内存泄漏及其检测工具

一.什么是内存泄露? 在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费. 通常我们所说的内存泄漏是指堆内存的泄漏.堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内存.应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或del

[转]浅谈C/C++内存泄露及其检测工具

转自:http://www.cnblogs.com/taoxu0903/archive/2007/10/27/939261.html 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garbage Collection等.Smart Pointer技术比较成熟,STL中已经包含支持Smart Pointer的class,但是它的使用似乎并不广泛,而且它也不能解决所有的问题:Garbage Collec