brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.4 KiB · 02ca823 Raw
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