Linux高级调试与优化——Address Sanitizer
Address Sanitizer
ASAN最早可以追溯到 LLVM 的 sanitizers项目(https://github.com/google/sanitizers),这个项目包含了AddressSanitizer,MemorySanitizer,ThreadSanitizer 和 LeakSanitizer等工具。这些工具可以检测用户空间的内存问题。通过在编译时加入指定的选项,就可以给用户程序加入 Address Sanitizer 功能。
其中Address Sanitizer(ASAN)工具是一个内存错误检测器,可以检测以下问题:
1)Out-of-bounds accesses to heap, stack and globals 堆、栈以及全局变量越界
2)Use-after-free 即访问dangling pointer,已经free的指针
3)Use-after-return (to some extent)
4)Double-free, invalid free
5)Memory leaks (experimental)
ASan基于shadow memory实现,目前已经集成到Clang 3.1和GCC 4.8以上版本。
编译选项
-fsanitize=address 使能Address Sanitizer工具
-fsanitize=leak 只使能Leak Sanitizer,检测内存泄漏问题
-fno-omit-frame-pointer 检测到内存错误时打印函数调用栈
-O1 代码优化选项,可以打印更清晰的函数调用栈
实例演示
1)栈溢出
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { int stack[100] = {0}; stack[100] = 0xdeadbeef; return 0; }
首先使用gcc stack-overflow.c -o stack-overflow编译,然后用./stack-overflow执行
linyao@chgao-virtual-machine:~/debugging/asan$ gcc stack-overflow.c -o stack-overflow
linyao@chgao-virtual-machine:~/debugging/asan$ ./stack-overflow
linyao@chgao-virtual-machine:~/debugging/asan$
程序没有任何报错,没有检测到栈越界。
接下来集成ASAN编译并执行,发现栈越界错误:
linyao@chgao-virtual-machine:~/debugging/asan$ gcc -fsanitize=address -fno-omit-frame-pointer stack-overflow.c -o stack-overflow linyao@chgao-virtual-machine:~/debugging/asan$ ./stack-overflow ================================================================= ==29781==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc6c0f67a0 at pc 0x0000004008fb bp 0x7ffc6c0f65d0 sp 0x7ffc6c0f65c0 WRITE of size 4 at 0x7ffc6c0f67a0 thread T0 #0 0x4008fa in main (/media/new/linyao/debugging/asan/stack-overflow+0x4008fa) #1 0x7fc449f7082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) #2 0x400748 in _start (/media/new/linyao/debugging/asan/stack-overflow+0x400748) Address 0x7ffc6c0f67a0 is located in stack of thread T0 at offset 432 in frame #0 0x400825 in main (/media/new/linyao/debugging/asan/stack-overflow+0x400825) This frame has 1 object(s): [32, 432) 'stack' <== Memory access at offset 432 overflows 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-overflow ??:0 main Shadow bytes around the buggy address: 0x10000d816ca0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10000d816cb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 0x10000d816cc0: f1 f1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10000d816cd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10000d816ce0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x10000d816cf0: 00 00 00 00[f4]f4 f3 f3 f3 f3 00 00 00 00 00 00 0x10000d816d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10000d816d10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10000d816d20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10000d816d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10000d816d40: 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: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right 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 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe ==29781==ABORTING
2)堆溢出
#include <stdio.h> #include <stdlib.h> #define HEAP_SIZE (100) int main(int argc, char **argv) { int *heap = NULL; heap = (int *)malloc(HEAP_SIZE * sizeof(int)); if (NULL == heap) return -1; *(heap + HEAP_SIZE) = 0xdeadbeef; return 0; }
编译并执行:
linyao@chgao-virtual-machine:~/debugging/asan$ gcc -fsanitize=address -fno-omit-frame-pointer heap-overflow.c -o heap-overflow linyao@chgao-virtual-machine:~/debugging/asan$ ./heap-overflow ================================================================= ==31287==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61400000ffd0 at pc 0x0000004007ab bp 0x7fffa2f87bd0 sp 0x7fffa2f87bc0 WRITE of size 4 at 0x61400000ffd0 thread T0 #0 0x4007aa in main (/media/new/linyao/debugging/asan/heap-overflow+0x4007aa) #1 0x7fc8239b682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) #2 0x400668 in _start (/media/new/linyao/debugging/asan/heap-overflow+0x400668) 0x61400000ffd0 is located 0 bytes to the right of 400-byte region [0x61400000fe40,0x61400000ffd0) allocated by thread T0 here: #0 0x7fc823df8602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602) #1 0x400756 in main (/media/new/linyao/debugging/asan/heap-overflow+0x400756) #2 0x7fc8239b682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 main Shadow bytes around the buggy address: 0x0c287fff9fa0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fff9fb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fff9fc0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00 0x0c287fff9fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c287fff9fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c287fff9ff0: 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa 0x0c287fffa000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fffa010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fffa020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fffa030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fffa040: 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 right 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 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe ==31287==ABORTING
KASAN(Kernel Address Sanitizer)
Andrey Ryabinin 借鉴了 AddressSanitizer 的思想,并在 Linux 内核中实现了 Kernel Address Sanitizer。所以 Kasan 也可以看成是用于内核空间的 Address Sanitizer。
Kasan 是内核的一部分,使用时需要重新配置、编译并安装内核。Kasan 在 Linux 内核 4.0 版本时被引入内核,所以选择的内核代码需要高于 4.0 版本。另外,最基本的 Kasan 功能需要 GCC4.9.2 支持,更多的支持则需要 GCC5.0 及以上版本。
Linux内核内存检查工具还有kmemcheck。另外,也可以通过使能SLAB_DEBUG/SLUB_DEBUG/DEBUG_SLAB/DEBUG_PAGEALLOC等内核配置选项监控内存使用情况。
Castle ActiveRecord学习实践(7):使用HQL查询
C#中废弃一个方法小技巧
加入BI团队,推荐一个商业智能的论坛
.NET设计模式(13):享元模式(Flyweight Pattern)
重载还是覆写?
Castle ActiveRecord学习实践(2):构建配置信息
使用WebClient上传文件时的错误问题解决
Castle ActiveRecord学习实践(5):实现Many–Many关系的映射
天津.NET俱乐部成立了!
- 最新文章
-
SAStruts/S2JDBC JSPで画面部品を作ってみる
はじめてのSAStruts 6週目
はじめてのSAStruts 4週目
S2JDBC DB2DialectでのforUpdate()を調べてみた
SAStruts リンク記述におけるs:linkとhtml:linkの比較
はじめてのSAStruts 5週目
一种基于so的C/C++服务热更新方案
linux下cp,mv进行动态库覆盖问题分析
linux下So覆盖导致coredump问题的分析
关于C ++:如何在Linux上热重载共享库
- 热门文章
-
图像视频编码和FFmpeg(3)用FFmpeg进行图像格式转换和AVFrame简介_luotuo44的专栏程序员资料_avframe格式转换
Delphi XE2 之 FireMonkey 入门(45) 结题与问题
MusicXML 3.0 (6) 符杠分组
Delphi XE2 新增 System.Zip 单元, 可用一句话压缩整个文件夹了
MusicXML 3.0 (1) "Hello World" in MusicXML
关于禁止程序重复启动的另一种需要与实现
MusicXML 3.0 (4) 谱号
MusicXML 3.0 (2) 调号
MusicXML 3.0 (5) 附点、休止符
MusicXML 3.0 (3) 拍号