Snaitizer家族,還有AddressSanitizer 和 MemorySanitizer
ThreadSanitizer又叫TSan,是一個檢查線程Data Race的C/C++工具。它集成在新版的gcc和clang中,通過編譯時加-fsanitize=thread,可以在運行時檢測出Data Race的問題。
ThreadSanitizer官網:https://code.google.com/p/thread-sanitizer
Data Race
Data Race是指多個線程在沒有正確加鎖的情況下,同時訪問同一塊數據,並且至少有一個線程是寫操作,對數據的讀取和修改產生了競爭,從而導致各種不可預計的問題。
Data Race的問題非常難查,Data Race一旦發生,結果是不可預期的,也許直接就Crash了,也許導致執行流程錯亂了,也許把內存破壞導致之後某個時刻突然Crash了。
環境要求
- Linux x86_64,內核版本不要太舊。(經測試,公司舊的開發機Linux內核是2.6.16是跑不了的,新的tlinux內核3.10.0可以)
- gcc 4.8版本以上(clang也集成了,3.2版本以上)
官方示例
$ cat simple_race.cc
#include <pthread.h>
#include <stdio.h>
int Global;
void *Thread1(void *x) {
Global++;
return NULL;
}
void *Thread2(void *x) {
Global--;
return NULL;
}
int main() {
pthread_t t[2];
pthread_create(&t[0], NULL, Thread1, NULL);
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
}
$ g++ simple_race.cc -fsanitize=thread -fPIE -pie -g
$ ./a.out
==================
WARNING: ThreadSanitizer: data race (pid=26327)
Write of size 4 at 0x7f89554701d0 by thread T1:
#0 Thread1(void*) simple_race.cc:8 (exe+0x000000006e66)
Previous write of size 4 at 0x7f89554701d0 by thread T2:
#0 Thread2(void*) simple_race.cc:13 (exe+0x000000006ed6)
Thread T1 (tid=26328, running) created at:
#0 pthread_create tsan_interceptors.cc:683 (exe+0x00000001108b)
#1 main simple_race.cc:19 (exe+0x000000006f39)
Thread T2 (tid=26329, running) created at:
#0 pthread_create tsan_interceptors.cc:683 (exe+0x00000001108b)
#1 main simple_race.cc:20 (exe+0x000000006f63)
==================
ThreadSanitizer: reported 1 warnings
執行程序,如果發生Data Race,錯誤信息會直接輸出出來。如果錯誤信息比較多,重定向輸出流到文件裏,慢慢分析:
$ ./a.out >result.txt 2>&1
關鍵要點
- 除了加-fsanitize=thread外,一定要加-fPIE -pie。
- -g 是爲了能顯示文件名和行號。
- 如果分生成obj(-c)和link兩個步驟,每一步都加:thread -fPIE -pie -g,並且在link的時候加-ltsan
- 只支持64位,最好指定編譯64位(-m64)
- 如果依賴其他靜態庫,其他靜態庫編譯時必須指定-fPIC(如果不是請重編)