【gcc / g++】Address Sanitizer(ASan)的介绍与使用详解:C/C++ 内存错误检测利器

📅 发布时间:2026/7/9 18:43:29 👁️ 浏览次数:
【gcc / g++】Address Sanitizer(ASan)的介绍与使用详解:C/C++ 内存错误检测利器
博客主页https://blog.csdn.net/wkd_007博客内容嵌入式开发、Linux、C语言、C、数据结构、音视频本文内容介绍 Address SanitizerASan 金句分享你不能选择最好的但最好的会来选择你——泰戈尔⏰发布时间⏰ 2025-09-29 08:00:00本文未经允许不得转发目录一、概述二、Address Sanitizer的使用✨2.1 判断编译器是否支持Address Sanitizer✨2.2Address Sanitizer的使用三、Address Sanitizer 使用的例子✨3.1 使用已释放的内存use-after-free✨3.2 堆缓冲区溢出heap-buffer-overflow✨3.3 栈缓冲区溢出stack-buffer-overflow✨3.4 全局变量溢出global-buffer-overflow✨3.5 函数返回后使用use-after-return✨3.6 作用域结束后使用use-after-scope✨3.7 内存泄漏memory leaks✨3.8 内存分配和释放的方式不匹配alloc-dealloc-mismatch四、Address Sanitizer的高级用法✨4.1 排除特定函数✨4.2 自定义 ASan 选项五、总结一、概述AddressSanitizer简称 ASan是 Google 开发的一种快速内存错误检测工具它集成在 Clang LLVM(版本3.1开始)、MSVC(版本16.4开始) 和 GNU GCC(版本4.8开始) 编译器中。ASan 能够检测多种内存访问错误包括使用已释放的内存use-after-free堆缓冲区溢出heap-buffer-overflow栈缓冲区溢出stack-buffer-overflow全局变量溢出global-buffer-overflow函数返回后使用use-after-return作用域结束后使用use-after-scope内存泄漏memory leaksASan 的主要优势在于其高性能 - 通常只会使程序运行速度降低约 2 倍而传统工具如 Valgrind 可能会降低 10-20 倍。AddressSanitizer的GitHub托管地址。本文主要从 Linux 系统的 GCC/G 编译器来介绍 Address SanitizerASan。二、Address Sanitizer的使用✨2.1 判断编译器是否支持Address Sanitizer在使用Address Sanitizer之前我们需要先判断当前编译器是否支持该功能。这里介绍的判断方式只针对GNU的GCC/G编译器主要分两个步骤执行1、看编译器版本号使用下面命令查看编译器版本号如果版本号小于4.8的则不支持Address Sanitizer功能gcc-vg-v2、查看编译器是否有libasan.so库先使用which命令找到编译器的安装目录然后使用find命令查找libasan.so库这个库是Address Sanitizer所依赖的库存在的话则说明支持该功能。whichgccfind/usr/lib/-namelibasan.so✨2.2Address Sanitizer的使用这里只介绍 GCC/G 编译器的使用。GCC/G编译器可以通过增加-fsanitizeaddress来启用Address Sanitizer功能若想在错误信息中看到更详细的堆栈跟踪信息请添加-fno-omit-frame-pointer选项。另外还有-g、-O选项也需要注意的。这几个编译选项具体如下-fsanitizeaddress选项启用 Address Sanitizer功能-g包含一些调试信息能够明确指出调用了某一行的代码方便定位问题。-O、-O1、-Os会进行代码优化提高程序性能。但测试过程中发现加了-O有时可能导致AddressSanitizer不报错。三、Address Sanitizer 使用的例子✨3.1 使用已释放的内存use-after-free#includestdlib.hvoiduse_after_free_example(){int*array(int*)malloc(10*sizeof(int));free(array);// 内存被释放// 错误使用已释放的内存array[0]42;// ASan 会在这里检测到错误}intmain(){use_after_free_example();return0;}编译gcc use_after_free.c -fsanitizeaddress -g运行结果✨3.2 堆缓冲区溢出heap-buffer-overflow#includestdlib.h#includestring.hvoidheap_overflow_example(){char*buffer(char*)malloc(10);// 错误写入超出分配的范围memset(buffer,A,15);// 只分配了10字节但写入了15字节free(buffer);}intmain(){heap_overflow_example();return0;}编译gcc heap_buffer_overflow.c -fsanitizeaddress -g运行结果✨3.3 栈缓冲区溢出stack-buffer-overflowvoidstack_overflow_example(){intstack_array[5];// 错误栈缓冲区溢出for(inti0;i10;i){stack_array[i]i;// 当 i 5 时溢出}}intmain(){stack_overflow_example();return0;}编译gcc stack_buffer_overflow.c -fsanitizeaddress -g运行结果✨3.4 全局变量溢出global-buffer-overflowintglobal_array[5]{0};voidglobal_overflow_example(){// 错误全局缓冲区溢出global_array[5]42;// 有效索引是 0-4}intmain(){global_overflow_example();return0;}编译gcc global_buffer_overflow.c -fsanitizeaddress -g运行结果✨3.5 函数返回后使用use-after-return#includestdio.hint*dangling_pointerNULL;voidcreate_dangling_pointer(){intlocal_var42;dangling_pointerlocal_var;// 函数返回后local_var 的生命周期结束return;}voiduse_after_return_example(){create_dangling_pointer();// 错误使用函数返回后的栈内存*dangling_pointer100;// ASan 会检测到这个问题printf(dangling%d\n,*dangling_pointer);}intmain(){use_after_return_example();return0;}编译gcc global_buffer_overflow.c -fsanitizeaddress -g注意需要设置环境变量来启用此检测export ASAN_OPTIONSdetect_stack_use_after_return1。运行结果✨3.6 作用域结束后使用use-after-scope#includestdio.hint*scope_pointerNULL;voiduse_after_scope_example(){{intlocal_var100;scope_pointerlocal_var;}// local_var 离开作用域// 错误使用作用域外的变量*scope_pointer200;// ASan 检测 use-after-scope}intmain(){use_after_scope_example();return0;}编译gcc use_after_scope.c -fsanitizeaddress -g注意有些编译器可能需要加上编译选项-fsanitize-address-use-after-scope。运行结果✨3.7 内存泄漏memory leaks#includestdlib.hvoidmemory_leak_example(){// 分配内存后没释放内存泄漏int*leaked_memory(int*)malloc(100*sizeof(int));leaked_memoryNULL;}intmain(){memory_leak_example();return0;}编译gcc memory_leaks.c -fsanitizeaddress -g运行结果✨3.8 内存分配和释放的方式不匹配alloc-dealloc-mismatch#includestdio.hintmain(){int*pInt(int*)newchar[sizeof(int)];deletepInt;return0;}编译g alloc-dealloc-mismatch.cpp -fsanitizeaddress -g运行结果四、Address Sanitizer的高级用法✨4.1 排除特定函数如果某些函数已知是安全的可以排除它们以提高性能// 在函数声明前添加属性__attribute__((no_sanitize(address)))voidsafe_function(){// 这个函数不会被 ASan 检测}✨4.2 自定义 ASan 选项通过环境变量控制 ASan 的行为# 启用更详细的输出exportASAN_OPTIONSverbosity1:log_pathasan.log# 禁用内存泄漏检测exportASAN_OPTIONSdetect_leaks0# 设置选项组合exportASAN_OPTIONS\detect_stack_use_after_return1:\check_initialization_order1:\detect_leaks1:\allocator_may_return_null1五、总结AddressSanitizer 是现代 C/C 开发中强大的内存安全检测工具能够有效识别 8 类常见内存错误。通过简单的编译选项即可启用结合详细的错误报告大大提高了内存相关问题的调试效率。最佳实践建议在开发测试阶段始终启用 ASan根据项目需求配置合适的检测选项结合 CI/CD 流程进行自动化检测注意平台差异和性能影响正确使用 ASan 可以显著提升代码质量和稳定性是每个 C/C 开发者应该掌握的重要工具。如果文章有帮助的话点赞、收藏⭐支持一波谢谢 参考Address Sanitizer InternalsGoogle Sanitizers 内存错误检测工具原理及使用https://zhuanlan.zhihu.com/p/10482716538Address Sanitizer 常见报错https://blog.csdn.net/kinbo88/article/details/104575247内存检查(AddressSanitizer的使用)https://blog.csdn.net/qq_36115224/article/details/120550963