AddressSanitizer是gcc和clang编译器内置的内存错误检测工具,能够在程序运行时发现堆、栈、全局变量区域的内存越界、使用已释放内存、内存泄漏等常见问题,相比传统调试工具定位效率更高。

asan的基本使用原理
asan会在编译阶段对代码进行插桩,在每次内存操作前后添加检查逻辑,同时会在内存区域周围设置红区,当程序访问到红区或者已释放的内存区域时,就会触发错误报告,输出详细的错误信息和调用栈。
编译阶段开启asan
使用gcc或者clang编译c++程序时,只需要添加对应的编译参数即可开启asan,不同编译器的参数略有区别。
gcc编译器配置
gcc从4.8版本开始支持asan,编译时添加-fsanitize=address参数,同时建议添加-g参数保留调试信息,方便定位错误位置。
// 编译单个cpp文件 g++ -fsanitize=address -g test.cpp -o test // 如果是多文件项目,每个编译单元都需要添加该参数 g++ -fsanitize=address -g main.cpp func.cpp -o app
clang编译器配置
clang的asan开启方式和gcc类似,同样使用-fsanitize=address参数,部分版本可能需要额外添加-fno-omit-frame-pointer参数保证调用栈信息完整。
clang++ -fsanitize=address -g -fno-omit-frame-pointer test.cpp -o test
常见内存错误检测示例
堆内存越界访问
堆内存越界是c++中最常见的内存错误之一,下面是一段触发堆越界的示例代码。
#include <iostream>
#include <cstdlib>
int main() {
// 分配10个int大小的内存
int* arr = new int[10];
// 越界访问第11个元素,触发asan错误
arr[10] = 100;
delete[] arr;
return 0;
}
编译运行后,asan会输出错误类型、越界的内存地址、访问大小以及完整的调用栈,能直接定位到越界访问的代码行。
使用已释放内存
释放内存后继续访问该内存区域也是常见错误,示例代码如下。
#include <iostream>
int main() {
int* p = new int(10);
delete p;
// 使用已释放的内存,触发asan错误
*p = 20;
return 0;
}
asan会检测到该操作属于use-after-free错误,同时会显示内存释放的位置和当前访问的位置。
栈内存越界
栈上的局部变量越界同样可以被asan检测到,示例代码如下。
#include <iostream>
int main() {
int stack_arr[5];
// 栈内存越界访问
stack_arr[5] = 10;
return 0;
}
asan的常用配置选项
可以通过环境变量对asan的行为进行配置,常用的配置项如下:
- ASAN_OPTIONS=detect_leaks=1:开启内存泄漏检测,默认情况下asan会检测内存泄漏,部分场景可能需要手动开启
- ASAN_OPTIONS=abort_on_error=1:检测到错误后立即终止程序,方便自动化测试场景使用
- ASAN_OPTIONS=print_stacktrace=1:强制输出调用栈信息,默认已经开启
设置环境变量的方式如下,在运行程序前执行:
export ASAN_OPTIONS=detect_leaks=1:abort_on_error=1 ./test
注意事项
使用asan时需要注意以下几点:
- 开启asan后程序运行速度会下降2-3倍,内存占用会增加2-3倍,不适合生产环境使用,仅用于调试阶段
- 如果项目使用了自定义的malloc/new实现,可能会和asan的内存管理逻辑冲突,需要暂时关闭自定义实现
- 部分老版本的编译器对asan的支持不完善,建议尽量使用较新版本的gcc或者clang
asan只能检测运行时的内存错误,无法检测编译期的语法错误,也不能覆盖所有场景的内存问题,需要结合其他调试工具共同使用。
AddressSanitizerc++内存错误检测asan使用方法修改时间:2026-07-10 07:54:29