目录
malloc函数的运行时库组成,在性能及检测内存错误方面都优于Valgrind。ASan作为编译器内置功能,支持检测各种内存错误:
堆内存溢出
栈上内存溢出
全局区缓存溢出
使用释放后的堆上内存
使用返回的栈上内存
使用退出作用域的变量
重复释放
无效释放
6.1 asan(内存检测)
6.2 ubsan(未定义行为检测), 有的时候debug的程序没问题,release的程序会奇奇怪怪的core dump掉,那么你需要做这个检测
6.3 tsan(线程安全检测),如标题;tsan有一个点需要注意,因为大家代码跑通后一般不会用tsan做检测,再者tsan出来时间不长,一些老的库会有非常多的线程安全问题。再加上检测条件非常严格。所以,大型项目第一用tsan做检查的时候,可能每一行都会有线程安全问题。
6.4 leak(泄露检测),被6.1包括了
6.5 如果我们有多个libasan.so,我们需要跟-L/path/to/lib
6.6 如果提示请加载PRELOAD,那么请export LD_PRELOAD=或者export LD_PRELOAD=/path/to/liblsan.so/libasan.so
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.3 LTS
Release: 20.04
Codename: focal
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- #include
- using namespace std;
- int main()
- {
- int *p = new int(5);
- std::cout << *p << std::endl;
- return 0;
- }
编译:g++ main.cpp -g -llsan -fsanitize=leak

第9行,是个总结,他会告诉你总共泄露了4bytes,这4bytes属于1次开辟的。
4-7行,我们这里只泄露了一次,如果多次的话会有多个4-7行,会告诉你那个线程开辟的空间,哪个线程释放的空间。并且打印出详细的开辟和释放的函数栈,当然我们注意第五行,我们用的malloc已经被替换成lsan下的malloc了。
第2行,错误类型。
- #include
- #include
- #include
-
- char* get_systeminfo()
- {
- char *p_system = (char*)malloc(38*sizeof(char));
- strcpy(p_system, "Linux version");
- return p_system;
- }
-
- int main()
- {
- printf("Linux version is:%s", get_systeminfo());
- return 0;
-
- }
编译运行输出:
- 需带上ASAN_OPTIONS=detect_leaks=1 环境变量参数启程序
- 编译:
- g++ -fsanitize=address -fno-omit-frame-pointer -o memory_leak_test main.cpp
- ASAN_OPTIONS=detect_leaks=1 ./memory_leak_test
-
- 输出:
- =================================================================
- ==73465==ERROR: LeakSanitizer: detected memory leaks
-
- Direct leak of 38 byte(s) in 1 object(s) allocated from:
- #0 0x7fc23737d808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
- #1 0x55d14d17b21e in get_systeminfo() (/home/wangji/文档/桌面/学习资料/C++/memory_leak_test+0x121e)
- #2 0x55d14d17b24d in main (/home/wangji/文档/桌面/学习资料/C++/memory_leak_test+0x124d)
- #3 0x7fc236d560b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x240b2)
-
- SUMMARY: AddressSanitizer: 38 byte(s) leaked in 1 allocation(s).
- #include
- #include
- #include
-
- int main()
- {
- char *heap_buf = (char*)malloc(32*sizeof(char));
- memcpy(heap_buf+30, "overflow", 8);//在heap_buf的第30个字节开始,拷贝8个字符
-
- free(heap_buf);
-
- return 0;
- }
编译:
gcc -fsanitize=address -fno-omit-frame-pointer -o heap_ovf_test main.c
./heap_ovf_test

可以看到asan报错:==74085==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000000030 at xxxx,下面也列出了发生heap-buffer-overflow时的调用链及heap buffer在哪里申请的。
- #include
- #include
-
- int main()
- {
- char stack_buf[4] = {0};
- strcpy(stack_buf, "1234");
-
- return 0;
- }
编译:
gcc -fsanitize=address -fno-omit-frame-pointer -o stack_ovf_test main.c
./stack_ovf_test

- #include
- #include
- #include
-
- int main()
- {
- char *p = (char*)malloc(32*sizeof(char));
- free(p);
-
- int a = p[1];
-
- return 0;
- }
编译:
gcc -fsanitize=address -fno-omit-frame-pointer -o dang_pointer main.c
./dang_pointer

- #include
- #include
- #include
- int *ptr;
- void get_pointer()
- {
- int local[10];
- ptr = &local[0];
- return;
- }
-
- int main()
- {
- get_pointer();
-
- printf("%d\n", *ptr);
-
- return 0;
-
- }
编译:
启用ASAN_OPTIONS=detect_stack_use_after_return=1标志,才能检测此种内存错误使用的情况
gcc -fsanitize=address -fno-omit-frame-pointer -o use_after_return main.c
ASAN_OPTIONS=detect_stack_use_after_return=1 ./use_after_return

- #include
- #include
- #include
-
- int main()
- {
- int *p;
- {
- int num = 10;
- p = #
- }
- printf("%d/n", *p);
-
- return 0;
-
- }
编译:
gcc -fsanitize=address -fno-omit-frame-pointer -o use-after-scope main.c
./use-after-scope

- #include
- #include
-
- int main()
- {
- char *p = (char*)malloc(32*sizeof(char));
- free(p);
- free(p);
-
- return 0;
- }
编译:
gcc -fsanitize=address -fno-omit-frame-pointer -o invalid_free_test main.c
./invalid_free_test

ASAN_OPTIONS='stack_trace_format="[frame=%n, function=%f, location=%S]"'参数启动程序

输出的调用链中信息更精确,可以对应到代码文件的具体某一行。