AddressSanitizer(简称ASan)是一款基于编译器的内存错误检测工具,已经被集成到GCC和Clang等主流C++编译器中,能够在程序运行时检测数组越界、使用已释放内存、重复释放内存、栈溢出等多种内存非法操作。它通过在内存分配时添加红区(Redzone)来监控内存访问行为,当发生越界访问等错误时会立即输出详细的错误信息和调用栈,帮助开发者快速定位问题根源。

AddressSanitizer的开启方式
要使用AddressSanitizer,只需要在编译C++程序时添加对应的编译选项即可,不同编译器的选项略有区别。
GCC编译器开启方式
如果使用GCC编译C++程序,添加-fsanitize=address选项即可开启AddressSanitizer,同时建议添加-g选项保留调试信息,方便查看错误对应的源码位置。
// 编译命令示例
// g++ -fsanitize=address -g main.cpp -o main
#include <iostream>
int main() {
int* arr = new int[10];
// 越界访问,触发ASan检测
arr[10] = 5;
delete[] arr;
return 0;
}
Clang编译器开启方式
Clang编译器的开启方式和GCC一致,同样使用-fsanitize=address和-g选项组合。
# Clang编译命令示例 clang++ -fsanitize=address -g main.cpp -o main
常见内存错误场景检测示例
堆缓冲区溢出
堆缓冲区溢出是最常见的内存错误之一,指访问堆上分配的内存区域之外的地址,下面的代码会触发AddressSanitizer报错。
#include <cstring>
int main() {
char* buffer = new char[5];
// 向5字节的缓冲区写入6字节内容,发生堆缓冲区溢出
strcpy(buffer, "hello");
delete[] buffer;
return 0;
}
运行编译后的程序,ASan会输出错误类型、越界的内存地址、分配和释放该内存的调用栈,以及对应的源码行号,开发者可以直接定位到问题代码。
使用已释放内存
内存被释放后再次访问也属于非法操作,这类错误在复杂程序中很难排查,AddressSanitizer可以有效检测此类问题。
int main() {
int* ptr = new int(10);
delete ptr;
// 使用已释放的内存,触发ASan检测
*ptr = 20;
return 0;
}
栈缓冲区溢出
栈上的数组越界访问同样会被AddressSanitizer检测到,示例如下:
int main() {
int stack_arr[5];
// 栈数组越界访问
for (int i = 0; i <= 5; i++) {
stack_arr[i] = i;
}
return 0;
}
AddressSanitizer的常用配置选项
可以通过环境变量ASAN_OPTIONS调整AddressSanitizer的行为,常见的配置项如下:
| 配置项 | 说明 | 默认值 |
|---|---|---|
| halt_on_error | 发生错误时是否立即终止程序,0为不终止,1为终止 | 1 |
| detect_stack_use_after_return | 是否检测返回后使用栈内存的错误 | 0 |
| malloc_context_size | 内存分配调用栈的记录深度 | 30 |
配置示例:如果需要开启返回后使用栈内存的检测,可以在运行程序前设置环境变量:
# Linux系统下设置环境变量 export ASAN_OPTIONS=detect_stack_use_after_return=1 # 运行程序 ./main
注意事项
- 开启AddressSanitizer后程序运行速度会有一定下降,通常是原速度的2倍左右,不适合用于生产环境,仅建议在开发和测试阶段使用。
- AddressSanitizer无法检测所有类型的内存错误,比如内存泄漏需要配合LeakSanitizer(通常和ASan一起开启)来检测。
- 如果程序使用了自定义的Memory Allocator,可能需要额外配置才能让AddressSanitizer正常工作。
通过合理使用AddressSanitizer,开发者可以在开发阶段就发现大部分内存相关的错误,减少线上问题的发生概率,提升C++程序的稳定性和安全性。
AddressSanitizerC++内存错误检测程序调试修改时间:2026-06-18 11:24:41