文章目录
1. 介绍
AddressSanitizer(ASan)是google开发的一个应用内存检查工具,性能据说比valgrind要好不少,可以配合clang或者GCC编译器使用,GCC需要4.8及以上版本。4.8版本GCC对AddressSanitizer支持有限,功能不太完善,输出的错误信息也不够友好,使用不太方便,建议使用4.9及以上版本。
详细了解AddressSanitizer信息可以访问其github项目地址:
https://github.com/google/sanitizers/wiki/AddressSanitizer
参考资料:
C/C++ 内存治理神器 – Google Sanitizers
AddressSanitizer(又名ASan)是C/C++的内存错误检测器。可以检测以下问题:
-
heap-buffer-overflow 堆溢出错误
-
heap-use-after-free 释放后使用错误
-
detected memory leaks 内存泄漏错误
-
double-free 错误
-
memcpy-param-overlap 内存拷贝重叠错误
-
stack-buffer-overflow 栈溢出错误
- stack-buffer-underflow 栈缓冲区下溢
- stack-use-after-return 在返回后使用堆栈内存
- stack-use-after-scope 使用超出范围的堆栈内存
- strncat-param-overlap
- alloc-dealloc-mismatch 申请和释放API不匹配错误
- allocation-size-too-big 错误
- calloc-overflow 错误
- global-buffer-overflow 全局缓冲区溢出
- new-delete-type-mismatch 错误
- Initialization order bugs – 初始化顺序bug
示例和类型参考:
AddressSanitizer 错误示例
注意:ASan是运行时的内存检查工具,逻辑代码必须被运行才能有效检测。
2. 使用
在gcc 4.8以上,编译器中带有libasan.a ,编译时加上
CFLAGS += -fsanitize=address -fno-omit-frame-pointer -fsanitize=leak -static-libasan
LDFLAGS += -fsanitize=address -fno-omit-frame-pointer -static-libasan
编译,链接时都加上liasan选项。
-fsanitize=address 是开启内存越界检测
-fsanitize=leak 开启内存泄漏检测
-fno-omit-frame-pointer 是去使能栈溢出保护
-static-libasan 是静态链接asan
静态链接的好处是,在编译时gcc会处理好asan,避免动态链接的asan依赖报错
3. 最简单的示例
编译时调用sanitizer
-g
是告诉编译器编译时把符号表等调试信息编译进来
-fsanitize=address
编译标志是告诉编译器编译时调用address sanitizer
-static-libasan
标志是告诉连接器,把address sanitizer库链接进来。
所以使用的时候,如果你的编译分两个命令,注意编译的时候要加
-g -fsanitize
标志。 然后链接的时候要加
-fsanitize -static-libasan
标志。举例如下:
gcc -c main.c -fsanitize=address -g
gcc main.o -o main -fsanitize=address -static-libasan
当然编译命令也可以一步到位如下
gcc main.c -o main -fsanitize=address -static-libasan -g
示例1:test1.cpp
#include <iostream>
int main() {
int *arr = new int[10];
int res = arr[10]; // index out of bounds
std::cout << res << std::endl;
delete[] arr;
return 0;
}
编译:g++ test.cpp -fsanitize=address -static-libasan -g
运行:./a.out
4. 各类型示例
参考资料:
AddressSanitizer 错误示例
编译:
g++ test.cpp -fsanitize=address -static-libasan -g
heap-use-after-free 释放后使用错误
#include <iostream>
// example1.cpp
// heap-use-after-free error
#include <stdlib.h>
int main() {
char *x = (char*)malloc(10 * sizeof(char));
free(x);
// ...
return x[5]; // Boom!
}
double free 错误
// example1.cpp
// double-free error
int main() {
int *x = new int[42];
delete [] x;
// ... some complex body of code
delete [] x;
return 0;
}
detected memory leaks 内存泄漏错误
#include <iostream>
int main() {
int *ptr = new int(-1);
std::cout << *ptr << std::endl;
// delete ptr;
return 0;
}
5. 参考资料