1//===-- tsan_interface_ann.cc ---------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is a part of ThreadSanitizer (TSan), a race detector. 11// 12//===----------------------------------------------------------------------===// 13#include "sanitizer_common/sanitizer_libc.h" 14#include "sanitizer_common/sanitizer_internal_defs.h" 15#include "sanitizer_common/sanitizer_placement_new.h" 16#include "sanitizer_common/sanitizer_stacktrace.h" 17#include "tsan_interface_ann.h" 18#include "tsan_mutex.h" 19#include "tsan_report.h" 20#include "tsan_rtl.h" 21#include "tsan_mman.h" 22#include "tsan_flags.h" 23#include "tsan_platform.h" 24#include "tsan_vector.h" 25 26#define CALLERPC ((uptr)__builtin_return_address(0)) 27 28using namespace __tsan; // NOLINT 29 30namespace __tsan { 31 32class ScopedAnnotation { 33 public: 34 ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l, 35 uptr pc) 36 : thr_(thr) { 37 FuncEntry(thr_, pc); 38 DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l); 39 } 40 41 ~ScopedAnnotation() { 42 FuncExit(thr_); 43 CheckNoLocks(thr_); 44 } 45 private: 46 ThreadState *const thr_; 47}; 48 49#define SCOPED_ANNOTATION(typ) \ 50 if (!flags()->enable_annotations) \ 51 return; \ 52 ThreadState *thr = cur_thread(); \ 53 const uptr caller_pc = (uptr)__builtin_return_address(0); \ 54 StatInc(thr, StatAnnotation); \ 55 StatInc(thr, Stat##typ); \ 56 ScopedAnnotation sa(thr, __func__, f, l, caller_pc); \ 57 const uptr pc = StackTrace::GetCurrentPc(); \ 58 (void)pc; \ 59/**/ 60 61static const int kMaxDescLen = 128; 62 63struct ExpectRace { 64 ExpectRace *next; 65 ExpectRace *prev; 66 atomic_uintptr_t hitcount; 67 atomic_uintptr_t addcount; 68 uptr addr; 69 uptr size; 70 char *file; 71 int line; 72 char desc[kMaxDescLen]; 73}; 74 75struct DynamicAnnContext { 76 Mutex mtx; 77 ExpectRace expect; 78 ExpectRace benign; 79 80 DynamicAnnContext() 81 : mtx(MutexTypeAnnotations, StatMtxAnnotations) { 82 } 83}; 84 85static DynamicAnnContext *dyn_ann_ctx; 86static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGNED(64); 87 88static void AddExpectRace(ExpectRace *list, 89 char *f, int l, uptr addr, uptr size, char *desc) { 90 ExpectRace *race = list->next; 91 for (; race != list; race = race->next) { 92 if (race->addr == addr && race->size == size) { 93 atomic_store_relaxed(&race->addcount, 94 atomic_load_relaxed(&race->addcount) + 1); 95 return; 96 } 97 } 98 race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace)); 99 race->addr = addr; 100 race->size = size; 101 race->file = f; 102 race->line = l; 103 race->desc[0] = 0; 104 atomic_store_relaxed(&race->hitcount, 0); 105 atomic_store_relaxed(&race->addcount, 1); 106 if (desc) { 107 int i = 0; 108 for (; i < kMaxDescLen - 1 && desc[i]; i++) 109 race->desc[i] = desc[i]; 110 race->desc[i] = 0; 111 } 112 race->prev = list; 113 race->next = list->next; 114 race->next->prev = race; 115 list->next = race; 116} 117 118static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) { 119 for (ExpectRace *race = list->next; race != list; race = race->next) { 120 uptr maxbegin = max(race->addr, addr); 121 uptr minend = min(race->addr + race->size, addr + size); 122 if (maxbegin < minend) 123 return race; 124 } 125 return 0; 126} 127 128static bool CheckContains(ExpectRace *list, uptr addr, uptr size) { 129 ExpectRace *race = FindRace(list, addr, size); 130 if (race == 0) 131 return false; 132 DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n", 133 race->desc, race->addr, (int)race->size, race->file, race->line); 134 atomic_fetch_add(&race->hitcount, 1, memory_order_relaxed); 135 return true; 136} 137 138static void InitList(ExpectRace *list) { 139 list->next = list; 140 list->prev = list; 141} 142 143void InitializeDynamicAnnotations() { 144 dyn_ann_ctx = new(dyn_ann_ctx_placeholder) DynamicAnnContext; 145 InitList(&dyn_ann_ctx->expect); 146 InitList(&dyn_ann_ctx->benign); 147} 148 149bool IsExpectedReport(uptr addr, uptr size) { 150 ReadLock lock(&dyn_ann_ctx->mtx); 151 if (CheckContains(&dyn_ann_ctx->expect, addr, size)) 152 return true; 153 if (CheckContains(&dyn_ann_ctx->benign, addr, size)) 154 return true; 155 return false; 156} 157 158static void CollectMatchedBenignRaces(Vector<ExpectRace> *matched, 159 int *unique_count, int *hit_count, atomic_uintptr_t ExpectRace::*counter) { 160 ExpectRace *list = &dyn_ann_ctx->benign; 161 for (ExpectRace *race = list->next; race != list; race = race->next) { 162 (*unique_count)++; 163 const uptr cnt = atomic_load_relaxed(&(race->*counter)); 164 if (cnt == 0) 165 continue; 166 *hit_count += cnt; 167 uptr i = 0; 168 for (; i < matched->Size(); i++) { 169 ExpectRace *race0 = &(*matched)[i]; 170 if (race->line == race0->line 171 && internal_strcmp(race->file, race0->file) == 0 172 && internal_strcmp(race->desc, race0->desc) == 0) { 173 atomic_fetch_add(&(race0->*counter), cnt, memory_order_relaxed); 174 break; 175 } 176 } 177 if (i == matched->Size()) 178 matched->PushBack(*race); 179 } 180} 181 182void PrintMatchedBenignRaces() { 183 Lock lock(&dyn_ann_ctx->mtx); 184 int unique_count = 0; 185 int hit_count = 0; 186 int add_count = 0; 187 Vector<ExpectRace> hit_matched(MBlockScopedBuf); 188 CollectMatchedBenignRaces(&hit_matched, &unique_count, &hit_count, 189 &ExpectRace::hitcount); 190 Vector<ExpectRace> add_matched(MBlockScopedBuf); 191 CollectMatchedBenignRaces(&add_matched, &unique_count, &add_count, 192 &ExpectRace::addcount); 193 if (hit_matched.Size()) { 194 Printf("ThreadSanitizer: Matched %d \"benign\" races (pid=%d):\n", 195 hit_count, (int)internal_getpid()); 196 for (uptr i = 0; i < hit_matched.Size(); i++) { 197 Printf("%d %s:%d %s\n", 198 atomic_load_relaxed(&hit_matched[i].hitcount), 199 hit_matched[i].file, hit_matched[i].line, hit_matched[i].desc); 200 } 201 } 202 if (hit_matched.Size()) { 203 Printf("ThreadSanitizer: Annotated %d \"benign\" races, %d unique" 204 " (pid=%d):\n", 205 add_count, unique_count, (int)internal_getpid()); 206 for (uptr i = 0; i < add_matched.Size(); i++) { 207 Printf("%d %s:%d %s\n", 208 atomic_load_relaxed(&add_matched[i].addcount), 209 add_matched[i].file, add_matched[i].line, add_matched[i].desc); 210 } 211 } 212} 213 214static void ReportMissedExpectedRace(ExpectRace *race) { 215 Printf("==================\n"); 216 Printf("WARNING: ThreadSanitizer: missed expected data race\n"); 217 Printf(" %s addr=%zx %s:%d\n", 218 race->desc, race->addr, race->file, race->line); 219 Printf("==================\n"); 220} 221} // namespace __tsan 222 223using namespace __tsan; // NOLINT 224 225extern "C" { 226void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) { 227 SCOPED_ANNOTATION(AnnotateHappensBefore); 228 Release(thr, pc, addr); 229} 230 231void INTERFACE_ATTRIBUTE AnnotateHappensAfter(char *f, int l, uptr addr) { 232 SCOPED_ANNOTATION(AnnotateHappensAfter); 233 Acquire(thr, pc, addr); 234} 235 236void INTERFACE_ATTRIBUTE AnnotateCondVarSignal(char *f, int l, uptr cv) { 237 SCOPED_ANNOTATION(AnnotateCondVarSignal); 238} 239 240void INTERFACE_ATTRIBUTE AnnotateCondVarSignalAll(char *f, int l, uptr cv) { 241 SCOPED_ANNOTATION(AnnotateCondVarSignalAll); 242} 243 244void INTERFACE_ATTRIBUTE AnnotateMutexIsNotPHB(char *f, int l, uptr mu) { 245 SCOPED_ANNOTATION(AnnotateMutexIsNotPHB); 246} 247 248void INTERFACE_ATTRIBUTE AnnotateCondVarWait(char *f, int l, uptr cv, 249 uptr lock) { 250 SCOPED_ANNOTATION(AnnotateCondVarWait); 251} 252 253void INTERFACE_ATTRIBUTE AnnotateRWLockCreate(char *f, int l, uptr m) { 254 SCOPED_ANNOTATION(AnnotateRWLockCreate); 255 MutexCreate(thr, pc, m, true, true, false); 256} 257 258void INTERFACE_ATTRIBUTE AnnotateRWLockCreateStatic(char *f, int l, uptr m) { 259 SCOPED_ANNOTATION(AnnotateRWLockCreateStatic); 260 MutexCreate(thr, pc, m, true, true, true); 261} 262 263void INTERFACE_ATTRIBUTE AnnotateRWLockDestroy(char *f, int l, uptr m) { 264 SCOPED_ANNOTATION(AnnotateRWLockDestroy); 265 MutexDestroy(thr, pc, m); 266} 267 268void INTERFACE_ATTRIBUTE AnnotateRWLockAcquired(char *f, int l, uptr m, 269 uptr is_w) { 270 SCOPED_ANNOTATION(AnnotateRWLockAcquired); 271 if (is_w) 272 MutexLock(thr, pc, m); 273 else 274 MutexReadLock(thr, pc, m); 275} 276 277void INTERFACE_ATTRIBUTE AnnotateRWLockReleased(char *f, int l, uptr m, 278 uptr is_w) { 279 SCOPED_ANNOTATION(AnnotateRWLockReleased); 280 if (is_w) 281 MutexUnlock(thr, pc, m); 282 else 283 MutexReadUnlock(thr, pc, m); 284} 285 286void INTERFACE_ATTRIBUTE AnnotateTraceMemory(char *f, int l, uptr mem) { 287 SCOPED_ANNOTATION(AnnotateTraceMemory); 288} 289 290void INTERFACE_ATTRIBUTE AnnotateFlushState(char *f, int l) { 291 SCOPED_ANNOTATION(AnnotateFlushState); 292} 293 294void INTERFACE_ATTRIBUTE AnnotateNewMemory(char *f, int l, uptr mem, 295 uptr size) { 296 SCOPED_ANNOTATION(AnnotateNewMemory); 297} 298 299void INTERFACE_ATTRIBUTE AnnotateNoOp(char *f, int l, uptr mem) { 300 SCOPED_ANNOTATION(AnnotateNoOp); 301} 302 303void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) { 304 SCOPED_ANNOTATION(AnnotateFlushExpectedRaces); 305 Lock lock(&dyn_ann_ctx->mtx); 306 while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) { 307 ExpectRace *race = dyn_ann_ctx->expect.next; 308 if (atomic_load_relaxed(&race->hitcount) == 0) { 309 ctx->nmissed_expected++; 310 ReportMissedExpectedRace(race); 311 } 312 race->prev->next = race->next; 313 race->next->prev = race->prev; 314 internal_free(race); 315 } 316} 317 318void INTERFACE_ATTRIBUTE AnnotateEnableRaceDetection( 319 char *f, int l, int enable) { 320 SCOPED_ANNOTATION(AnnotateEnableRaceDetection); 321 // FIXME: Reconsider this functionality later. It may be irrelevant. 322} 323 324void INTERFACE_ATTRIBUTE AnnotateMutexIsUsedAsCondVar( 325 char *f, int l, uptr mu) { 326 SCOPED_ANNOTATION(AnnotateMutexIsUsedAsCondVar); 327} 328 329void INTERFACE_ATTRIBUTE AnnotatePCQGet( 330 char *f, int l, uptr pcq) { 331 SCOPED_ANNOTATION(AnnotatePCQGet); 332} 333 334void INTERFACE_ATTRIBUTE AnnotatePCQPut( 335 char *f, int l, uptr pcq) { 336 SCOPED_ANNOTATION(AnnotatePCQPut); 337} 338 339void INTERFACE_ATTRIBUTE AnnotatePCQDestroy( 340 char *f, int l, uptr pcq) { 341 SCOPED_ANNOTATION(AnnotatePCQDestroy); 342} 343 344void INTERFACE_ATTRIBUTE AnnotatePCQCreate( 345 char *f, int l, uptr pcq) { 346 SCOPED_ANNOTATION(AnnotatePCQCreate); 347} 348 349void INTERFACE_ATTRIBUTE AnnotateExpectRace( 350 char *f, int l, uptr mem, char *desc) { 351 SCOPED_ANNOTATION(AnnotateExpectRace); 352 Lock lock(&dyn_ann_ctx->mtx); 353 AddExpectRace(&dyn_ann_ctx->expect, 354 f, l, mem, 1, desc); 355 DPrintf("Add expected race: %s addr=%zx %s:%d\n", desc, mem, f, l); 356} 357 358static void BenignRaceImpl( 359 char *f, int l, uptr mem, uptr size, char *desc) { 360 Lock lock(&dyn_ann_ctx->mtx); 361 AddExpectRace(&dyn_ann_ctx->benign, 362 f, l, mem, size, desc); 363 DPrintf("Add benign race: %s addr=%zx %s:%d\n", desc, mem, f, l); 364} 365 366// FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm. 367void INTERFACE_ATTRIBUTE AnnotateBenignRaceSized( 368 char *f, int l, uptr mem, uptr size, char *desc) { 369 SCOPED_ANNOTATION(AnnotateBenignRaceSized); 370 BenignRaceImpl(f, l, mem, size, desc); 371} 372 373void INTERFACE_ATTRIBUTE AnnotateBenignRace( 374 char *f, int l, uptr mem, char *desc) { 375 SCOPED_ANNOTATION(AnnotateBenignRace); 376 BenignRaceImpl(f, l, mem, 1, desc); 377} 378 379void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) { 380 SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin); 381 ThreadIgnoreBegin(thr, pc); 382} 383 384void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) { 385 SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd); 386 ThreadIgnoreEnd(thr, pc); 387} 388 389void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) { 390 SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin); 391 ThreadIgnoreBegin(thr, pc); 392} 393 394void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) { 395 SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd); 396 ThreadIgnoreEnd(thr, pc); 397} 398 399void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncBegin(char *f, int l) { 400 SCOPED_ANNOTATION(AnnotateIgnoreSyncBegin); 401 ThreadIgnoreSyncBegin(thr, pc); 402} 403 404void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncEnd(char *f, int l) { 405 SCOPED_ANNOTATION(AnnotateIgnoreSyncEnd); 406 ThreadIgnoreSyncEnd(thr, pc); 407} 408 409void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange( 410 char *f, int l, uptr addr, uptr size) { 411 SCOPED_ANNOTATION(AnnotatePublishMemoryRange); 412} 413 414void INTERFACE_ATTRIBUTE AnnotateUnpublishMemoryRange( 415 char *f, int l, uptr addr, uptr size) { 416 SCOPED_ANNOTATION(AnnotateUnpublishMemoryRange); 417} 418 419void INTERFACE_ATTRIBUTE AnnotateThreadName( 420 char *f, int l, char *name) { 421 SCOPED_ANNOTATION(AnnotateThreadName); 422 ThreadSetName(thr, name); 423} 424 425// We deliberately omit the implementation of WTFAnnotateHappensBefore() and 426// WTFAnnotateHappensAfter(). Those are being used by Webkit to annotate 427// atomic operations, which should be handled by ThreadSanitizer correctly. 428void INTERFACE_ATTRIBUTE WTFAnnotateHappensBefore(char *f, int l, uptr addr) { 429 SCOPED_ANNOTATION(AnnotateHappensBefore); 430} 431 432void INTERFACE_ATTRIBUTE WTFAnnotateHappensAfter(char *f, int l, uptr addr) { 433 SCOPED_ANNOTATION(AnnotateHappensAfter); 434} 435 436void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized( 437 char *f, int l, uptr mem, uptr sz, char *desc) { 438 SCOPED_ANNOTATION(AnnotateBenignRaceSized); 439 BenignRaceImpl(f, l, mem, sz, desc); 440} 441 442int INTERFACE_ATTRIBUTE RunningOnValgrind() { 443 return flags()->running_on_valgrind; 444} 445 446double __attribute__((weak)) INTERFACE_ATTRIBUTE ValgrindSlowdown(void) { 447 return 10.0; 448} 449 450const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) { 451 if (internal_strcmp(query, "pure_happens_before") == 0) 452 return "1"; 453 else 454 return "0"; 455} 456 457void INTERFACE_ATTRIBUTE 458AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {} 459void INTERFACE_ATTRIBUTE 460AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {} 461} // extern "C" 462