翼度科技»论坛 云主机 LINUX 查看内容

内存检测工具——ASan(AddressSanitizer)的介绍和使用

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
ASan介绍

ASan全称AddressSanitizer,是一种内存错误检测工具,目的是帮助开发者检测和调试内存相关的问题,如使用未分配的内存、使用已释放的内存、堆内存溢出等。ASan是由Google开发的,广泛用于C、C++等语言的代码中。
ASan的工作原理是在编译时将额外的代码插入到目标程序中,对内存的读写操作进行检测和记录。当程序运行时,ASan会监测内存访问,一旦发现内存访问错误,比如越界访问、释放后再次访问等,会立即输出错误信息并中断程序执行,同时提供详细的报告帮助开发者定位问题的源头。
通过使用ASan,开发者可以在早期阶段发现和解决潜在的内存错误问题,有效提高程序的稳定性和安全性。ASan在调试阶段是一个非常有用的工具,但由于其会引入一些性能开销,因此在生产环境中通常不建议启用ASan。

ASan使用

要使用ASan,你需要使用支持ASan的编译器,如Clang或GCC,并开启ASan相关的编译选项。

  • 使用Clang编译器,在终端执行以下命令:
  1. clang -fsanitize=address -g your_program.c -o your_program
复制代码

  • 使用GCC编译器,在终端执行以下命令:
  1. gcc -fsanitize=address -g your_program.c -o your_program
复制代码
在上述命令中,-fsanitize=address是ASan的编译选项,用于开启ASan。-g选项用于生成调试符号,以支持调试和定位错误。当然,我们也可以通过环境变量的方式加入ASan编译选项,然后编译额时候需要加上环境变量,一般是CFLAGS或者CXXFLAGS。更推荐这种方式,因为通过makefile方式编译的时候,这种方式经常见。
  1. export CFLAGS="-fsanitize=address -g $CFLAGS"
  2. gcc $CFLAGS your_program.c -o your_program
复制代码
编译完成后,运行生成的可执行文件,ASan会在运行时监测程序的内存访问情况,并在发现错误时提供详细的错误信息,包括错误的位置和类型。
下面是一个使用C语言编写的示例程序,可以用来使用ASan进行内存错误检测
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. void leak_memory() {
  4.     int* p = malloc(sizeof(int) * 10);
  5.     // 没有释放内存,导致内存泄漏
  6. }
  7. int main() {
  8.     int* arr = malloc(sizeof(int) * 5);
  9.     arr[5] = 10; // 内存访问越界错误
  10.     free(arr); // 使用 free 释放内存
  11.     int* p = malloc(sizeof(int));
  12.     free(p); // 使用 free 释放内存
  13.     int* q = NULL;
  14.     *q = 5; // 使用空指针访问内存错误
  15.     leak_memory();
  16.     return 0;
  17. }
复制代码
编译并运行
  1. gcc $CFLAGS  asan.c -o asan
  2. ./asan
复制代码
一切顺利的话,会输出下面这种异常。
  1. =================================================================
  2. ==296710==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xffff7b700b64 at pc 0x000000400810 bp 0xffffd7b963b0 sp 0xffffd7b963a0
  3. WRITE of size 4 at 0xffff7b700b64 thread T0
  4.     #0 0x40080c in main /home/test/asan.c:11
  5.     #1 0xffff7f38df38 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
  6.     #2 0xffff7f38e004 in __libc_start_main_impl ../csu/libc-start.c:409
  7.     #3 0x4006ac in _start (/home/test/asan+0x4006ac)
  8. 0xffff7b700b64 is located 0 bytes to the right of 20-byte region [0xffff7b700b50,0xffff7b700b64)
  9. allocated by thread T0 here:
  10.     #0 0xffff7f5a6080 in malloc (/usr/lib64/libasan.so.6+0xa9080)
  11.     #1 0x4007b0 in main /home/test/asan.c:10
  12.     #2 0xffff7f38df38 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
  13.     #3 0xffff7f38e004 in __libc_start_main_impl ../csu/libc-start.c:409
  14.     #4 0x4006ac in _start (/home/test/asan+0x4006ac)
  15. SUMMARY: AddressSanitizer: heap-buffer-overflow /home/test/asan.c:11 in main
  16. Shadow bytes around the buggy address:
  17.   0x200fef6e0110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  18.   0x200fef6e0120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  19.   0x200fef6e0130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  20.   0x200fef6e0140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  21.   0x200fef6e0150: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  22. =>0x200fef6e0160: fa fa fa fa fa fa fa fa fa fa 00 00[04]fa fa fa
  23.   0x200fef6e0170: 00 00 00 fa fa fa fa fa fa fa fa fa fa fa fa fa
  24.   0x200fef6e0180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  25.   0x200fef6e0190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  26.   0x200fef6e01a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  27.   0x200fef6e01b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  28. Shadow byte legend (one shadow byte represents 8 application bytes):
  29.   Addressable:           00
  30.   Partially addressable: 01 02 03 04 05 06 07
  31.   Heap left redzone:       fa
  32.   Freed heap region:       fd
  33.   Stack left redzone:      f1
  34.   Stack mid redzone:       f2
  35.   Stack right redzone:     f3
  36.   Stack after return:      f5
  37.   Stack use after scope:   f8
  38.   Global redzone:          f9
  39.   Global init order:       f6
  40.   Poisoned by user:        f7
  41.   Container overflow:      fc
  42.   Array cookie:            ac
  43.   Intra object redzone:    bb
  44.   ASan internal:           fe
  45.   Left alloca redzone:     ca
  46.   Right alloca redzone:    cb
  47.   Shadow gap:              cc
  48. ==296710==ABORTING
复制代码
看堆栈调用信息可以看到
  1. #0 0x40080c in main /home/test/asan.c:11
复制代码
在asan.c文件中的第11行出现了异常,我们看第11行可以知道,只有5个元素,却要访问第6个元素,导致了数组溢出。
如果你修改好了第11行,重新编译运行,会发现还会有其他异常,可以动手自己实验,把这个程序修复好。
需要特别特别注意的是,ASan会增加程序的运行时间和内存开销,因此主要用于调试和测试阶段,特别不建议在生产环境中启用。
ASan其他选项

除了 -fsanitize=address 外,还有其他 AddressSanitizer 相关的编译选项可供选择。以下是一些常用的 AddressSanitizer 编译选项及其作用:

  • Memory Sanitizer (-fsanitize=memory):用于检测对未初始化内存或使用已释放内存的操作。这个选项可以帮助发现一些难以察觉的内存错误。
  • UndefinedBehaviorSanitizer (-fsanitize=undefined):用于检测未定义行为,例如整数溢出、空指针解引用等问题。这有助于发现代码中的潜在 bug。
  • Thread Sanitizer (-fsanitize=thread):用于检测多线程程序中的数据竞争和死锁问题。这个选项可以帮助识别并修复多线程程序中的并发 bug。
  • Address Sanitizer with Leak Detection (-fsanitize=leak):启用 AddressSanitizer 的同时,也检测内存泄漏问题。这个选项有助于发现代码中的内存泄漏 bug。
  • Coverage Sanitizer (-fsanitize=coverage):用于生成代码覆盖率报告,检测程序中哪些部分被执行过。这个选项通常用于代码覆盖率测试和分析。
  • Kernel Address Sanitizer (-fsanitize=kernel-address):针对 Linux 内核模块开发,用于检测内核中的内存错误。
参考资料

以下是一些比较权威的关于AddressSanitizer的资料,大多数都是英文,有兴趣可以看看。
https://clang.llvm.org/docs/AddressSanitizer.html
https://github.com/google/sanitizers/wiki/AddressSanitizer
https://learn.microsoft.com/zh-tw/cpp/sanitizers/asan
更多精彩内容,请关注同名公众:一点sir(alittle-sir)

来源:https://www.cnblogs.com/kiwiblog/p/18084121
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具