diff options
Diffstat (limited to 'lib/tsan/rtl/tsan_interface_ann.cc')
-rw-r--r-- | lib/tsan/rtl/tsan_interface_ann.cc | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/lib/tsan/rtl/tsan_interface_ann.cc b/lib/tsan/rtl/tsan_interface_ann.cc new file mode 100644 index 0000000..a605b6c --- /dev/null +++ b/lib/tsan/rtl/tsan_interface_ann.cc @@ -0,0 +1,352 @@ +//===-- tsan_interface_ann.cc ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer (TSan), a race detector. +// +//===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_placement_new.h" +#include "tsan_interface_ann.h" +#include "tsan_mutex.h" +#include "tsan_report.h" +#include "tsan_rtl.h" +#include "tsan_mman.h" +#include "tsan_flags.h" +#include "tsan_platform.h" + +#define CALLERPC ((uptr)__builtin_return_address(0)) + +using namespace __tsan; // NOLINT + +namespace __tsan { + +class ScopedAnnotation { + public: + ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l, + uptr pc) + : thr_(thr) + , in_rtl_(thr->in_rtl) { + CHECK_EQ(thr_->in_rtl, 0); + FuncEntry(thr_, pc); + thr_->in_rtl++; + DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l); + } + + ~ScopedAnnotation() { + thr_->in_rtl--; + CHECK_EQ(in_rtl_, thr_->in_rtl); + FuncExit(thr_); + } + private: + ThreadState *const thr_; + const int in_rtl_; +}; + +#define SCOPED_ANNOTATION(typ) \ + if (!flags()->enable_annotations) \ + return; \ + ThreadState *thr = cur_thread(); \ + StatInc(thr, StatAnnotation); \ + StatInc(thr, Stat##typ); \ + ScopedAnnotation sa(thr, __FUNCTION__, f, l, \ + (uptr)__builtin_return_address(0)); \ + const uptr pc = (uptr)&__FUNCTION__; \ + (void)pc; \ +/**/ + +static const int kMaxDescLen = 128; + +struct ExpectRace { + ExpectRace *next; + ExpectRace *prev; + int hitcount; + uptr addr; + uptr size; + char *file; + int line; + char desc[kMaxDescLen]; +}; + +struct DynamicAnnContext { + Mutex mtx; + ExpectRace expect; + ExpectRace benign; + + DynamicAnnContext() + : mtx(MutexTypeAnnotations, StatMtxAnnotations) { + } +}; + +static DynamicAnnContext *dyn_ann_ctx; +static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGNED(64); + +static void AddExpectRace(ExpectRace *list, + char *f, int l, uptr addr, uptr size, char *desc) { + ExpectRace *race = list->next; + for (; race != list; race = race->next) { + if (race->addr == addr && race->size == size) + return; + } + race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace)); + race->hitcount = 0; + race->addr = addr; + race->size = size; + race->file = f; + race->line = l; + race->desc[0] = 0; + if (desc) { + int i = 0; + for (; i < kMaxDescLen - 1 && desc[i]; i++) + race->desc[i] = desc[i]; + race->desc[i] = 0; + } + race->prev = list; + race->next = list->next; + race->next->prev = race; + list->next = race; +} + +static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) { + for (ExpectRace *race = list->next; race != list; race = race->next) { + uptr maxbegin = max(race->addr, addr); + uptr minend = min(race->addr + race->size, addr + size); + if (maxbegin < minend) + return race; + } + return 0; +} + +static bool CheckContains(ExpectRace *list, uptr addr, uptr size) { + ExpectRace *race = FindRace(list, addr, size); + if (race == 0 && AlternativeAddress(addr)) + race = FindRace(list, AlternativeAddress(addr), size); + if (race == 0) + return false; + DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n", + race->desc, race->addr, (int)race->size, race->file, race->line); + race->hitcount++; + return true; +} + +static void InitList(ExpectRace *list) { + list->next = list; + list->prev = list; +} + +void InitializeDynamicAnnotations() { + dyn_ann_ctx = new(dyn_ann_ctx_placeholder) DynamicAnnContext; + InitList(&dyn_ann_ctx->expect); + InitList(&dyn_ann_ctx->benign); +} + +bool IsExpectedReport(uptr addr, uptr size) { + Lock lock(&dyn_ann_ctx->mtx); + if (CheckContains(&dyn_ann_ctx->expect, addr, size)) + return true; + if (CheckContains(&dyn_ann_ctx->benign, addr, size)) + return true; + return false; +} + +} // namespace __tsan + +using namespace __tsan; // NOLINT + +extern "C" { +void AnnotateHappensBefore(char *f, int l, uptr addr) { + SCOPED_ANNOTATION(AnnotateHappensBefore); + Release(cur_thread(), CALLERPC, addr); +} + +void AnnotateHappensAfter(char *f, int l, uptr addr) { + SCOPED_ANNOTATION(AnnotateHappensAfter); + Acquire(cur_thread(), CALLERPC, addr); +} + +void AnnotateCondVarSignal(char *f, int l, uptr cv) { + SCOPED_ANNOTATION(AnnotateCondVarSignal); +} + +void AnnotateCondVarSignalAll(char *f, int l, uptr cv) { + SCOPED_ANNOTATION(AnnotateCondVarSignalAll); +} + +void AnnotateMutexIsNotPHB(char *f, int l, uptr mu) { + SCOPED_ANNOTATION(AnnotateMutexIsNotPHB); +} + +void AnnotateCondVarWait(char *f, int l, uptr cv, uptr lock) { + SCOPED_ANNOTATION(AnnotateCondVarWait); +} + +void AnnotateRWLockCreate(char *f, int l, uptr lock) { + SCOPED_ANNOTATION(AnnotateRWLockCreate); +} + +void AnnotateRWLockDestroy(char *f, int l, uptr lock) { + SCOPED_ANNOTATION(AnnotateRWLockDestroy); +} + +void AnnotateRWLockAcquired(char *f, int l, uptr lock, uptr is_w) { + SCOPED_ANNOTATION(AnnotateRWLockAcquired); +} + +void AnnotateRWLockReleased(char *f, int l, uptr lock, uptr is_w) { + SCOPED_ANNOTATION(AnnotateRWLockReleased); +} + +void AnnotateTraceMemory(char *f, int l, uptr mem) { + SCOPED_ANNOTATION(AnnotateTraceMemory); +} + +void AnnotateFlushState(char *f, int l) { + SCOPED_ANNOTATION(AnnotateFlushState); +} + +void AnnotateNewMemory(char *f, int l, uptr mem, uptr size) { + SCOPED_ANNOTATION(AnnotateNewMemory); +} + +void AnnotateNoOp(char *f, int l, uptr mem) { + SCOPED_ANNOTATION(AnnotateNoOp); +} + +static void ReportMissedExpectedRace(ExpectRace *race) { + TsanPrintf("==================\n"); + TsanPrintf("WARNING: ThreadSanitizer: missed expected data race\n"); + TsanPrintf(" %s addr=%zx %s:%d\n", + race->desc, race->addr, race->file, race->line); + TsanPrintf("==================\n"); +} + +void AnnotateFlushExpectedRaces(char *f, int l) { + SCOPED_ANNOTATION(AnnotateFlushExpectedRaces); + Lock lock(&dyn_ann_ctx->mtx); + while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) { + ExpectRace *race = dyn_ann_ctx->expect.next; + if (race->hitcount == 0) { + CTX()->nmissed_expected++; + ReportMissedExpectedRace(race); + } + race->prev->next = race->next; + race->next->prev = race->prev; + internal_free(race); + } +} + +void AnnotateEnableRaceDetection(char *f, int l, int enable) { + SCOPED_ANNOTATION(AnnotateEnableRaceDetection); + // FIXME: Reconsider this functionality later. It may be irrelevant. +} + +void AnnotateMutexIsUsedAsCondVar(char *f, int l, uptr mu) { + SCOPED_ANNOTATION(AnnotateMutexIsUsedAsCondVar); +} + +void AnnotatePCQGet(char *f, int l, uptr pcq) { + SCOPED_ANNOTATION(AnnotatePCQGet); +} + +void AnnotatePCQPut(char *f, int l, uptr pcq) { + SCOPED_ANNOTATION(AnnotatePCQPut); +} + +void AnnotatePCQDestroy(char *f, int l, uptr pcq) { + SCOPED_ANNOTATION(AnnotatePCQDestroy); +} + +void AnnotatePCQCreate(char *f, int l, uptr pcq) { + SCOPED_ANNOTATION(AnnotatePCQCreate); +} + +void AnnotateExpectRace(char *f, int l, uptr mem, char *desc) { + SCOPED_ANNOTATION(AnnotateExpectRace); + Lock lock(&dyn_ann_ctx->mtx); + AddExpectRace(&dyn_ann_ctx->expect, + f, l, mem, 1, desc); + DPrintf("Add expected race: %s addr=%zx %s:%d\n", desc, mem, f, l); +} + +static void BenignRaceImpl(char *f, int l, uptr mem, uptr size, char *desc) { + Lock lock(&dyn_ann_ctx->mtx); + AddExpectRace(&dyn_ann_ctx->benign, + f, l, mem, size, desc); + DPrintf("Add benign race: %s addr=%zx %s:%d\n", desc, mem, f, l); +} + +// FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm. +void AnnotateBenignRaceSized(char *f, int l, uptr mem, uptr size, char *desc) { + SCOPED_ANNOTATION(AnnotateBenignRaceSized); + BenignRaceImpl(f, l, mem, size, desc); +} + +void AnnotateBenignRace(char *f, int l, uptr mem, char *desc) { + SCOPED_ANNOTATION(AnnotateBenignRace); + BenignRaceImpl(f, l, mem, 1, desc); +} + +void AnnotateIgnoreReadsBegin(char *f, int l) { + SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin); + IgnoreCtl(cur_thread(), false, true); +} + +void AnnotateIgnoreReadsEnd(char *f, int l) { + SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd); + IgnoreCtl(cur_thread(), false, false); +} + +void AnnotateIgnoreWritesBegin(char *f, int l) { + SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin); + IgnoreCtl(cur_thread(), true, true); +} + +void AnnotateIgnoreWritesEnd(char *f, int l) { + SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd); + IgnoreCtl(cur_thread(), true, false); +} + +void AnnotatePublishMemoryRange(char *f, int l, uptr addr, uptr size) { + SCOPED_ANNOTATION(AnnotatePublishMemoryRange); +} + +void AnnotateUnpublishMemoryRange(char *f, int l, uptr addr, uptr size) { + SCOPED_ANNOTATION(AnnotateUnpublishMemoryRange); +} + +void AnnotateThreadName(char *f, int l, char *name) { + SCOPED_ANNOTATION(AnnotateThreadName); +} + +void WTFAnnotateHappensBefore(char *f, int l, uptr addr) { + SCOPED_ANNOTATION(AnnotateHappensBefore); +} + +void WTFAnnotateHappensAfter(char *f, int l, uptr addr) { + SCOPED_ANNOTATION(AnnotateHappensAfter); +} + +void WTFAnnotateBenignRaceSized(char *f, int l, uptr mem, uptr sz, char *desc) { + SCOPED_ANNOTATION(AnnotateBenignRaceSized); +} + +int RunningOnValgrind() { + return flags()->running_on_valgrind; +} + +double __attribute__((weak)) ValgrindSlowdown(void) { + return 10.0; +} + +const char *ThreadSanitizerQuery(const char *query) { + if (internal_strcmp(query, "pure_happens_before") == 0) + return "1"; + else + return "0"; +} +} // extern "C" |