475 lines · cpp
1//===-- tsan_interface_ann.cpp --------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of ThreadSanitizer (TSan), a race detector.10//11//===----------------------------------------------------------------------===//12#include "sanitizer_common/sanitizer_libc.h"13#include "sanitizer_common/sanitizer_internal_defs.h"14#include "sanitizer_common/sanitizer_placement_new.h"15#include "sanitizer_common/sanitizer_stacktrace.h"16#include "sanitizer_common/sanitizer_vector.h"17#include "tsan_interface_ann.h"18#include "tsan_report.h"19#include "tsan_rtl.h"20#include "tsan_mman.h"21#include "tsan_flags.h"22#include "tsan_platform.h"23 24#define CALLERPC ((uptr)__builtin_return_address(0))25 26using namespace __tsan;27 28namespace __tsan {29 30class ScopedAnnotation {31 public:32 ScopedAnnotation(ThreadState *thr, const char *aname, uptr pc)33 : thr_(thr) {34 FuncEntry(thr_, pc);35 DPrintf("#%d: annotation %s()\n", thr_->tid, aname);36 }37 38 ~ScopedAnnotation() {39 FuncExit(thr_);40 CheckedMutex::CheckNoLocks();41 }42 private:43 ThreadState *const thr_;44};45 46#define SCOPED_ANNOTATION_RET(typ, ret) \47 if (!flags()->enable_annotations) \48 return ret; \49 ThreadState *thr = cur_thread(); \50 const uptr caller_pc = (uptr)__builtin_return_address(0); \51 ScopedAnnotation sa(thr, __func__, caller_pc); \52 const uptr pc = StackTrace::GetCurrentPc(); \53 (void)pc;54 55#define SCOPED_ANNOTATION(typ) SCOPED_ANNOTATION_RET(typ, )56 57static const int kMaxDescLen = 128;58 59struct ExpectRace {60 ExpectRace *next;61 ExpectRace *prev;62 atomic_uintptr_t hitcount;63 atomic_uintptr_t addcount;64 uptr addr;65 uptr size;66 char *file;67 int line;68 char desc[kMaxDescLen];69};70 71struct DynamicAnnContext {72 Mutex mtx;73 ExpectRace benign;74 75 DynamicAnnContext() : mtx(MutexTypeAnnotations) {}76};77 78static DynamicAnnContext *dyn_ann_ctx;79alignas(64) static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)];80 81static void AddExpectRace(ExpectRace *list,82 char *f, int l, uptr addr, uptr size, char *desc) {83 ExpectRace *race = list->next;84 for (; race != list; race = race->next) {85 if (race->addr == addr && race->size == size) {86 atomic_store_relaxed(&race->addcount,87 atomic_load_relaxed(&race->addcount) + 1);88 return;89 }90 }91 race = static_cast<ExpectRace *>(Alloc(sizeof(ExpectRace)));92 race->addr = addr;93 race->size = size;94 race->file = f;95 race->line = l;96 race->desc[0] = 0;97 atomic_store_relaxed(&race->hitcount, 0);98 atomic_store_relaxed(&race->addcount, 1);99 if (desc) {100 int i = 0;101 for (; i < kMaxDescLen - 1 && desc[i]; i++)102 race->desc[i] = desc[i];103 race->desc[i] = 0;104 }105 race->prev = list;106 race->next = list->next;107 race->next->prev = race;108 list->next = race;109}110 111static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) {112 for (ExpectRace *race = list->next; race != list; race = race->next) {113 uptr maxbegin = max(race->addr, addr);114 uptr minend = min(race->addr + race->size, addr + size);115 if (maxbegin < minend)116 return race;117 }118 return 0;119}120 121static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {122 ExpectRace *race = FindRace(list, addr, size);123 if (race == 0)124 return false;125 DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n",126 race->desc, race->addr, (int)race->size, race->file, race->line);127 atomic_fetch_add(&race->hitcount, 1, memory_order_relaxed);128 return true;129}130 131static void InitList(ExpectRace *list) {132 list->next = list;133 list->prev = list;134}135 136void InitializeDynamicAnnotations() {137 dyn_ann_ctx = new(dyn_ann_ctx_placeholder) DynamicAnnContext;138 InitList(&dyn_ann_ctx->benign);139}140 141bool IsExpectedReport(uptr addr, uptr size) {142 ReadLock lock(&dyn_ann_ctx->mtx);143 return CheckContains(&dyn_ann_ctx->benign, addr, size);144}145} // namespace __tsan146 147using namespace __tsan;148 149extern "C" {150void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) {151 SCOPED_ANNOTATION(AnnotateHappensBefore);152 Release(thr, pc, addr);153}154 155void INTERFACE_ATTRIBUTE AnnotateHappensAfter(char *f, int l, uptr addr) {156 SCOPED_ANNOTATION(AnnotateHappensAfter);157 Acquire(thr, pc, addr);158}159 160void INTERFACE_ATTRIBUTE AnnotateCondVarSignal(char *f, int l, uptr cv) {161}162 163void INTERFACE_ATTRIBUTE AnnotateCondVarSignalAll(char *f, int l, uptr cv) {164}165 166void INTERFACE_ATTRIBUTE AnnotateMutexIsNotPHB(char *f, int l, uptr mu) {167}168 169void INTERFACE_ATTRIBUTE AnnotateCondVarWait(char *f, int l, uptr cv,170 uptr lock) {171}172 173void INTERFACE_ATTRIBUTE AnnotateRWLockCreate(char *f, int l, uptr m) {174 SCOPED_ANNOTATION(AnnotateRWLockCreate);175 MutexCreate(thr, pc, m, MutexFlagWriteReentrant);176}177 178void INTERFACE_ATTRIBUTE AnnotateRWLockCreateStatic(char *f, int l, uptr m) {179 SCOPED_ANNOTATION(AnnotateRWLockCreateStatic);180 MutexCreate(thr, pc, m, MutexFlagWriteReentrant | MutexFlagLinkerInit);181}182 183void INTERFACE_ATTRIBUTE AnnotateRWLockDestroy(char *f, int l, uptr m) {184 SCOPED_ANNOTATION(AnnotateRWLockDestroy);185 MutexDestroy(thr, pc, m);186}187 188void INTERFACE_ATTRIBUTE AnnotateRWLockAcquired(char *f, int l, uptr m,189 uptr is_w) {190 SCOPED_ANNOTATION(AnnotateRWLockAcquired);191 if (is_w)192 MutexPostLock(thr, pc, m, MutexFlagDoPreLockOnPostLock);193 else194 MutexPostReadLock(thr, pc, m, MutexFlagDoPreLockOnPostLock);195}196 197void INTERFACE_ATTRIBUTE AnnotateRWLockReleased(char *f, int l, uptr m,198 uptr is_w) {199 SCOPED_ANNOTATION(AnnotateRWLockReleased);200 if (is_w)201 MutexUnlock(thr, pc, m);202 else203 MutexReadUnlock(thr, pc, m);204}205 206void INTERFACE_ATTRIBUTE AnnotateTraceMemory(char *f, int l, uptr mem) {207}208 209void INTERFACE_ATTRIBUTE AnnotateFlushState(char *f, int l) {210}211 212void INTERFACE_ATTRIBUTE AnnotateNewMemory(char *f, int l, uptr mem,213 uptr size) {214}215 216void INTERFACE_ATTRIBUTE AnnotateNoOp(char *f, int l, uptr mem) {217}218 219void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) {220}221 222void INTERFACE_ATTRIBUTE AnnotateEnableRaceDetection(223 char *f, int l, int enable) {224}225 226void INTERFACE_ATTRIBUTE AnnotateMutexIsUsedAsCondVar(227 char *f, int l, uptr mu) {228}229 230void INTERFACE_ATTRIBUTE AnnotatePCQGet(231 char *f, int l, uptr pcq) {232}233 234void INTERFACE_ATTRIBUTE AnnotatePCQPut(235 char *f, int l, uptr pcq) {236}237 238void INTERFACE_ATTRIBUTE AnnotatePCQDestroy(239 char *f, int l, uptr pcq) {240}241 242void INTERFACE_ATTRIBUTE AnnotatePCQCreate(243 char *f, int l, uptr pcq) {244}245 246void INTERFACE_ATTRIBUTE AnnotateExpectRace(247 char *f, int l, uptr mem, char *desc) {248}249 250static void BenignRaceImpl(char *f, int l, uptr mem, uptr size, char *desc) {251 Lock lock(&dyn_ann_ctx->mtx);252 AddExpectRace(&dyn_ann_ctx->benign,253 f, l, mem, size, desc);254 DPrintf("Add benign race: %s addr=%zx %s:%d\n", desc, mem, f, l);255}256 257void INTERFACE_ATTRIBUTE AnnotateBenignRaceSized(258 char *f, int l, uptr mem, uptr size, char *desc) {259 SCOPED_ANNOTATION(AnnotateBenignRaceSized);260 BenignRaceImpl(f, l, mem, size, desc);261}262 263void INTERFACE_ATTRIBUTE AnnotateBenignRace(264 char *f, int l, uptr mem, char *desc) {265 SCOPED_ANNOTATION(AnnotateBenignRace);266 BenignRaceImpl(f, l, mem, 1, desc);267}268 269void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) {270 SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);271 ThreadIgnoreBegin(thr, pc);272}273 274void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) {275 SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);276 ThreadIgnoreEnd(thr);277}278 279void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) {280 SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);281 ThreadIgnoreBegin(thr, pc);282}283 284void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) {285 SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);286 ThreadIgnoreEnd(thr);287}288 289void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncBegin(char *f, int l) {290 SCOPED_ANNOTATION(AnnotateIgnoreSyncBegin);291 ThreadIgnoreSyncBegin(thr, pc);292}293 294void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncEnd(char *f, int l) {295 SCOPED_ANNOTATION(AnnotateIgnoreSyncEnd);296 ThreadIgnoreSyncEnd(thr);297}298 299void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange(300 char *f, int l, uptr addr, uptr size) {301}302 303void INTERFACE_ATTRIBUTE AnnotateUnpublishMemoryRange(304 char *f, int l, uptr addr, uptr size) {305}306 307void INTERFACE_ATTRIBUTE AnnotateThreadName(308 char *f, int l, char *name) {309 SCOPED_ANNOTATION(AnnotateThreadName);310 ThreadSetName(thr, name);311}312 313// We deliberately omit the implementation of WTFAnnotateHappensBefore() and314// WTFAnnotateHappensAfter(). Those are being used by Webkit to annotate315// atomic operations, which should be handled by ThreadSanitizer correctly.316void INTERFACE_ATTRIBUTE WTFAnnotateHappensBefore(char *f, int l, uptr addr) {317}318 319void INTERFACE_ATTRIBUTE WTFAnnotateHappensAfter(char *f, int l, uptr addr) {320}321 322void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized(323 char *f, int l, uptr mem, uptr sz, char *desc) {324 SCOPED_ANNOTATION(AnnotateBenignRaceSized);325 BenignRaceImpl(f, l, mem, sz, desc);326}327 328int INTERFACE_ATTRIBUTE RunningOnValgrind() {329 return flags()->running_on_valgrind;330}331 332double __attribute__((weak)) INTERFACE_ATTRIBUTE ValgrindSlowdown(void) {333 return 10.0;334}335 336const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) {337 if (internal_strcmp(query, "pure_happens_before") == 0)338 return "1";339 else340 return "0";341}342 343void INTERFACE_ATTRIBUTE344AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}345void INTERFACE_ATTRIBUTE346AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {}347 348// Note: the parameter is called flagz, because flags is already taken349// by the global function that returns flags.350INTERFACE_ATTRIBUTE351void __tsan_mutex_create(void *m, unsigned flagz) {352 SCOPED_ANNOTATION(__tsan_mutex_create);353 MutexCreate(thr, pc, (uptr)m, flagz & MutexCreationFlagMask);354}355 356INTERFACE_ATTRIBUTE357void __tsan_mutex_destroy(void *m, unsigned flagz) {358 SCOPED_ANNOTATION(__tsan_mutex_destroy);359 MutexDestroy(thr, pc, (uptr)m, flagz);360}361 362INTERFACE_ATTRIBUTE363void __tsan_mutex_pre_lock(void *m, unsigned flagz) {364 SCOPED_ANNOTATION(__tsan_mutex_pre_lock);365 if (!(flagz & MutexFlagTryLock)) {366 if (flagz & MutexFlagReadLock)367 MutexPreReadLock(thr, pc, (uptr)m);368 else369 MutexPreLock(thr, pc, (uptr)m);370 }371 ThreadIgnoreBegin(thr, 0);372 ThreadIgnoreSyncBegin(thr, 0);373}374 375INTERFACE_ATTRIBUTE376void __tsan_mutex_post_lock(void *m, unsigned flagz, int rec) {377 SCOPED_ANNOTATION(__tsan_mutex_post_lock);378 ThreadIgnoreSyncEnd(thr);379 ThreadIgnoreEnd(thr);380 if (!(flagz & MutexFlagTryLockFailed)) {381 if (flagz & MutexFlagReadLock)382 MutexPostReadLock(thr, pc, (uptr)m, flagz);383 else384 MutexPostLock(thr, pc, (uptr)m, flagz, rec);385 }386}387 388INTERFACE_ATTRIBUTE389int __tsan_mutex_pre_unlock(void *m, unsigned flagz) {390 SCOPED_ANNOTATION_RET(__tsan_mutex_pre_unlock, 0);391 int ret = 0;392 if (flagz & MutexFlagReadLock) {393 CHECK(!(flagz & MutexFlagRecursiveUnlock));394 MutexReadUnlock(thr, pc, (uptr)m);395 } else {396 ret = MutexUnlock(thr, pc, (uptr)m, flagz);397 }398 ThreadIgnoreBegin(thr, 0);399 ThreadIgnoreSyncBegin(thr, 0);400 return ret;401}402 403INTERFACE_ATTRIBUTE404void __tsan_mutex_post_unlock(void *m, unsigned flagz) {405 SCOPED_ANNOTATION(__tsan_mutex_post_unlock);406 ThreadIgnoreSyncEnd(thr);407 ThreadIgnoreEnd(thr);408}409 410INTERFACE_ATTRIBUTE411void __tsan_mutex_pre_signal(void *addr, unsigned flagz) {412 SCOPED_ANNOTATION(__tsan_mutex_pre_signal);413 ThreadIgnoreBegin(thr, 0);414 ThreadIgnoreSyncBegin(thr, 0);415}416 417INTERFACE_ATTRIBUTE418void __tsan_mutex_post_signal(void *addr, unsigned flagz) {419 SCOPED_ANNOTATION(__tsan_mutex_post_signal);420 ThreadIgnoreSyncEnd(thr);421 ThreadIgnoreEnd(thr);422}423 424INTERFACE_ATTRIBUTE425void __tsan_mutex_pre_divert(void *addr, unsigned flagz) {426 SCOPED_ANNOTATION(__tsan_mutex_pre_divert);427 // Exit from ignore region started in __tsan_mutex_pre_lock/unlock/signal.428 ThreadIgnoreSyncEnd(thr);429 ThreadIgnoreEnd(thr);430}431 432INTERFACE_ATTRIBUTE433void __tsan_mutex_post_divert(void *addr, unsigned flagz) {434 SCOPED_ANNOTATION(__tsan_mutex_post_divert);435 ThreadIgnoreBegin(thr, 0);436 ThreadIgnoreSyncBegin(thr, 0);437}438 439static void ReportMutexHeldWrongContext(ThreadState *thr, uptr pc) {440 // Use alloca, because malloc during signal handling deadlocks441 ScopedReport *rep = (ScopedReport *)__builtin_alloca(sizeof(ScopedReport));442 // Take a new scope as Apple platforms require the below locks released443 // before symbolizing in order to avoid a deadlock444 {445 ThreadRegistryLock l(&ctx->thread_registry);446 new (rep) ScopedReport(ReportTypeMutexHeldWrongContext);447 for (uptr i = 0; i < thr->mset.Size(); ++i) {448 MutexSet::Desc desc = thr->mset.Get(i);449 rep->AddMutex(desc.addr, desc.stack_id);450 }451 VarSizeStackTrace trace;452 ObtainCurrentStack(thr, pc, &trace);453 rep->AddStack(trace, true);454#if SANITIZER_APPLE455 } // Close this scope to release the locks456#endif457 OutputReport(thr, *rep);458 459 // Need to manually destroy this because we used placement new to allocate460 rep->~ScopedReport();461#if !SANITIZER_APPLE462 }463#endif464}465 466INTERFACE_ATTRIBUTE467void __tsan_check_no_mutexes_held() {468 SCOPED_ANNOTATION(__tsan_check_no_mutexes_held);469 if (thr->mset.Size() == 0) {470 return;471 }472 ReportMutexHeldWrongContext(thr, pc);473}474} // extern "C"475