Clang已经更新到11版,支持的功能也更多,从代码质量的角度来讲,越多的Sanitizer,可以检测出来的问题也越多。Clang-11支持以下的Sanitizer
- Address Sanitizer
- Memory Sanitizer
- Thread Sanitizer
- Undefined Behavior Sanitizer
- Leak Sanitizer
下面分别讲讲这几个Sanitizer如何来使用。
Address Sanitizer
注意Address Sanitizer是没有False Alarm的,也就是没有误报。
可以检测出的错误:
1. Out-of-bounds accesses to heap, stack and globals
2. Use-after-free
3. Use-after-return (runtime flag ASAN_OPTIONS=detect_stack_use_after_return=1)
4. Use-after-scope (clang flag -fsanitize-address-use-after-scope)
5. Double-free, invalid free
6. Memory leaks (experimental)(default on linux, enabled by ASAN_OPTIONS=detect_leaks=1 on MacOs)
如何编译:
% cat example_UseAfterFree.cc
int main(int argc, char **argv) {
int *array = new int[100];
delete [] array;
return array[argc]; // BOOM
}
# Compile and link
% clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls example_UseAfterFree.cc
执行执行编译好的文件,如果AddressSanitizer检测出问题,就会立刻停止,并输出错误信息,不过错误信息里面只有地址,并不好分析。如果需要把地址和源代码对应起来,需要设置ASAN_SYMBOLIZER_PATH的环境变量,让它指向llvm-symbolizer,或者把llvm-symbolizer放在$PATH中。
% ASAN_SYMBOLIZER_PATH=/usr/local/bin/llvm-symbolizer ./a.out
==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8
READ of size 4 at 0x7f7ddab8c084 thread T0
#0 0x403c8c in main example_UseAfterFree.cc:4
#1 0x7f7ddabcac4d in __libc_start_main ??:0
0x7f7ddab8c084 is located 4 bytes inside of 400-byte region [0x7f7ddab8c080,0x7f7ddab8c210)
freed by thread T0 here:
#0 0x404704 in operator delete[](void*) ??:0
#1 0x403c53 in main example_UseAfterFree.cc:4
#2 0x7f7ddabcac4d in __libc_start_main ??:0
previously allocated by thread T0 here:
#0 0x404544 in operator new[](unsigned long) ??:0
#1 0x403c43 in main example_UseAfterFree.cc:2
#2 0x7f7ddabcac4d in __libc_start_main ??:0
==9442== ABORTING
Memory Sanitizer
可以检测出的错误:
uninitialized reads
如何编译:
% cat umr.cc
#include <stdio.h>
int main(int argc, char** argv) {
int* a = new int[10];
a[5] = 0;
if (a[argc])
printf("xx\n");
return 0;
}
% clang -fsanitize=memory -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -O1 umr.cc
另外,可以加上-fsanitize-memory-track-origins
去跟踪是未初始化的内存从哪里分配的;
执行:
% ./a.out
WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7f45944b418a in main umr.cc:6
#1 0x7f45938b676c in __libc_start_main libc-start.c:226
Thread Sanitizer
用来检测data races;
如何编译:
% cat projects/compiler-rt/lib/tsan/lit_tests/tiny_race.c
#include <pthread.h>
int Global;
void *Thread1(void *x) {
Global = 42;
return x;
}
int main() {
pthread_t t;
pthread_create(&t, NULL, Thread1, NULL);
Global = 43;
pthread_join(t, NULL);
return Global;
}
$ clang -fsanitize=thread -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -O1 tiny_race.c
执行过程中,如果检测到错误,会打印出来,但不会停下来:
WARNING: ThreadSanitizer: data race (pid=19219)
Write of size 4 at 0x7fcf47b21bc0 by thread T1:
#0 Thread1 tiny_race.c:4 (exe+0x00000000a360)
Previous write of size 4 at 0x7fcf47b21bc0 by main thread:
#0 main tiny_race.c:10 (exe+0x00000000a3b4)
Thread T1 (running) created at:
#0 pthread_create tsan_interceptors.cc:705 (exe+0x00000000c790)
#1 main tiny_race.c:9 (exe+0x00000000a3a4)
UndefinedBehaviorSanitizer
主要用于检测下面的错误;
1. Using misaligned or null pointer
2. Signed integer overflow
3.Conversion to, from, or between floating-point types which would overflow the destination
如何编译:
int main(int argc, char **argv) {
int k = 0x7fffffff;
k += argc;
return 0;
}
% clang++ -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -O1 test.cc
% ./a.out
test.cc:3:5: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
Leak Sanitizer
可以放在Address Sanitizer里面使用。
网友评论