一、AddressSanitizer
主要可以检测以下错误:
- Use after free:访问堆上已经被释放的内存
- Heap buffer overflow:堆上缓冲区访问溢出
- Stack buffer overflow:栈上缓冲区访问溢出
- Global buffer overflow:全局缓冲区访问溢出
- Use after return:访问栈上已被释放的内存
- Use after scope:栈对象使用超过定义范围
- Initialization order bugs:初始化命令错误
- Memory leaks:内存泄漏
详细使用方法请参考:
https://clang.llvm.org/docs/AddressSanitizer.html
二、example
我是在学习 vpp 源码时发现的这个好用的工具,对于自己实现的内存池使用很有效。
该工具已经集成到 gcc/clang 中了,使用很方便,下面给出一个 gcc 例子。
1. test.c
#include <sanitizer/asan_interface.h>
#include <stdio.h>
#include <stdlib.h>
#define MEM_POISON(ptr, size) ASAN_POISON_MEMORY_REGION(ptr, size)
#define MEM_UNPOISON(ptr, size) ASAN_UNPOISON_MEMORY_REGION(ptr, size)
#define INT_SIZE sizeof(int)
#define MEM_MAX 10
static int g_mem[MEM_MAX];
int main(int argc, char **argv)
{
int i, *a = g_mem;
for (i = 0; i < MEM_MAX; i++)
a[i] = i;
MEM_POISON(a, INT_SIZE * MEM_MAX);
MEM_UNPOISON(a, INT_SIZE * MEM_MAX);
for (i = 0; i < MEM_MAX; i++)
printf("%d ", a[i]);
MEM_POISON(a + (MEM_MAX >> 1), INT_SIZE * (MEM_MAX >> 1));
printf("\nFree the last half of the memory\n");
for (i = 0; i < MEM_MAX; i++)
printf("%d\n", a[i]);
return 0;
}
编译时要加上 -fsanitize=address
gcc -g -fsanitize=address -o out.exe test.c
2. output
后面报错省略,可以看到访问到地址 5 时便发生了错误。
0 1 2 3 4 5 6 7 8 9
Free the last half of the memory
0
1
2
3
4
=================================================================
==1807==ERROR: AddressSanitizer: use-after-poison on address 0x559a6be68174
.....................