diff options
Diffstat (limited to 'libsanitizer/tsan/tsan_rtl_mutex.cc')
-rw-r--r-- | libsanitizer/tsan/tsan_rtl_mutex.cc | 114 |
1 files changed, 68 insertions, 46 deletions
diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cc b/libsanitizer/tsan/tsan_rtl_mutex.cc index 3724571cfff..cc183138aba 100644 --- a/libsanitizer/tsan/tsan_rtl_mutex.cc +++ b/libsanitizer/tsan/tsan_rtl_mutex.cc @@ -50,14 +50,18 @@ void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) { static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ, uptr addr, u64 mid) { + // In Go, these misuses are either impossible, or detected by std lib, + // or false positives (e.g. unlock in a different thread). + if (kGoMode) + return; ThreadRegistryLock l(ctx->thread_registry); ScopedReport rep(typ); rep.AddMutex(mid); StackTrace trace; trace.ObtainCurrent(thr, pc); - rep.AddStack(&trace); + rep.AddStack(&trace, true); rep.AddLocation(addr, 1); - OutputReport(ctx, rep, rep.GetReport()->stacks[0]); + OutputReport(thr, rep); } void MutexCreate(ThreadState *thr, uptr pc, uptr addr, @@ -70,10 +74,12 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr, MemoryWrite(thr, pc, addr, kSizeLog1); thr->is_freeing = false; } - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); s->is_rw = rw; s->is_recursive = recursive; s->is_linker_init = linker_init; + if (kCppMode && s->creation_stack_id == 0) + s->creation_stack_id = CurrentStackId(thr, pc); s->mtx.Unlock(); } @@ -86,37 +92,54 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { if (IsGlobalVar(addr)) return; #endif - SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr); - if (s == 0) - return; - if (flags()->detect_deadlocks) { - Callback cb(thr, pc); - ctx->dd->MutexDestroy(&cb, &s->dd); - } if (IsAppMem(addr)) { CHECK(!thr->is_freeing); thr->is_freeing = true; MemoryWrite(thr, pc, addr, kSizeLog1); thr->is_freeing = false; } + SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr); + if (s == 0) + return; + if (common_flags()->detect_deadlocks) { + Callback cb(thr, pc); + ctx->dd->MutexDestroy(&cb, &s->dd); + ctx->dd->MutexInit(&cb, &s->dd); + } + bool unlock_locked = false; if (flags()->report_destroy_locked && s->owner_tid != SyncVar::kInvalidTid && !s->is_broken) { s->is_broken = true; + unlock_locked = true; + } + u64 mid = s->GetId(); + u32 last_lock = s->last_lock; + if (!unlock_locked) + s->Reset(thr); // must not reset it before the report is printed + s->mtx.Unlock(); + if (unlock_locked) { ThreadRegistryLock l(ctx->thread_registry); ScopedReport rep(ReportTypeMutexDestroyLocked); - rep.AddMutex(s); + rep.AddMutex(mid); StackTrace trace; trace.ObtainCurrent(thr, pc); rep.AddStack(&trace); - FastState last(s->last_lock); + FastState last(last_lock); RestoreStack(last.tid(), last.epoch(), &trace, 0); - rep.AddStack(&trace); - rep.AddLocation(s->addr, 1); - OutputReport(ctx, rep, rep.GetReport()->stacks[0]); + rep.AddStack(&trace, true); + rep.AddLocation(addr, 1); + OutputReport(thr, rep); + } + if (unlock_locked) { + SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr); + if (s != 0) { + s->Reset(thr); + s->mtx.Unlock(); + } } - thr->mset.Remove(s->GetId()); - DestroyAndFree(s); + thr->mset.Remove(mid); + // s will be destroyed and freed in MetaMap::FreeBlock. } void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) { @@ -124,7 +147,7 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) { CHECK_GT(rec, 0); if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId()); bool report_double_lock = false; @@ -147,7 +170,7 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) { } s->recursion += rec; thr->mset.Add(s->GetId(), true, thr->fast_state.epoch()); - if (flags()->detect_deadlocks && s->recursion == 1) { + if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) { Callback cb(thr, pc); if (!try_lock) ctx->dd->MutexBeforeLock(&cb, &s->dd, true); @@ -158,7 +181,7 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) { // Can't touch s after this point. if (report_double_lock) ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid); - if (flags()->detect_deadlocks) { + if (common_flags()->detect_deadlocks) { Callback cb(thr, pc); ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); } @@ -168,12 +191,12 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all); if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); int rec = 0; bool report_bad_unlock = false; - if (s->recursion == 0 || s->owner_tid != thr->tid) { + if (kCppMode && (s->recursion == 0 || s->owner_tid != thr->tid)) { if (flags()->report_mutex_bugs && !s->is_broken) { s->is_broken = true; report_bad_unlock = true; @@ -190,7 +213,8 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { } } thr->mset.Del(s->GetId(), true); - if (flags()->detect_deadlocks && s->recursion == 0) { + if (common_flags()->detect_deadlocks && s->recursion == 0 && + !report_bad_unlock) { Callback cb(thr, pc); ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true); } @@ -199,7 +223,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { // Can't touch s after this point. if (report_bad_unlock) ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); - if (flags()->detect_deadlocks) { + if (common_flags()->detect_deadlocks && !report_bad_unlock) { Callback cb(thr, pc); ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); } @@ -211,7 +235,7 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) { StatInc(thr, StatMutexReadLock); if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, false); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId()); bool report_bad_lock = false; @@ -224,7 +248,7 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) { AcquireImpl(thr, pc, &s->clock); s->last_lock = thr->fast_state.raw(); thr->mset.Add(s->GetId(), false, thr->fast_state.epoch()); - if (flags()->detect_deadlocks && s->recursion == 0) { + if (common_flags()->detect_deadlocks && s->recursion == 0) { Callback cb(thr, pc); if (!trylock) ctx->dd->MutexBeforeLock(&cb, &s->dd, false); @@ -235,7 +259,7 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) { // Can't touch s after this point. if (report_bad_lock) ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid); - if (flags()->detect_deadlocks) { + if (common_flags()->detect_deadlocks) { Callback cb(thr, pc); ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); } @@ -246,7 +270,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { StatInc(thr, StatMutexReadUnlock); if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); bool report_bad_unlock = false; @@ -257,7 +281,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { } } ReleaseImpl(thr, pc, &s->read_clock); - if (flags()->detect_deadlocks && s->recursion == 0) { + if (common_flags()->detect_deadlocks && s->recursion == 0) { Callback cb(thr, pc); ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false); } @@ -267,7 +291,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { thr->mset.Del(mid, false); if (report_bad_unlock) ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid); - if (flags()->detect_deadlocks) { + if (common_flags()->detect_deadlocks) { Callback cb(thr, pc); ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); } @@ -277,7 +301,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr); if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); bool write = true; bool report_bad_unlock = false; if (s->owner_tid == SyncVar::kInvalidTid) { @@ -305,7 +329,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { report_bad_unlock = true; } thr->mset.Del(s->GetId(), write); - if (flags()->detect_deadlocks && s->recursion == 0) { + if (common_flags()->detect_deadlocks && s->recursion == 0) { Callback cb(thr, pc); ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write); } @@ -314,7 +338,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { // Can't touch s after this point. if (report_bad_unlock) ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); - if (flags()->detect_deadlocks) { + if (common_flags()->detect_deadlocks) { Callback cb(thr, pc); ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); } @@ -322,7 +346,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { void MutexRepair(ThreadState *thr, uptr pc, uptr addr) { DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr); - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); s->owner_tid = SyncVar::kInvalidTid; s->recursion = 0; s->mtx.Unlock(); @@ -332,7 +356,7 @@ void Acquire(ThreadState *thr, uptr pc, uptr addr) { DPrintf("#%d: Acquire %zx\n", thr->tid, addr); if (thr->ignore_sync) return; - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, false); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); AcquireImpl(thr, pc, &s->clock); s->mtx.ReadUnlock(); } @@ -359,7 +383,7 @@ void Release(ThreadState *thr, uptr pc, uptr addr) { DPrintf("#%d: Release %zx\n", thr->tid, addr); if (thr->ignore_sync) return; - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); thr->fast_state.IncrementEpoch(); // Can't increment epoch w/o writing to the trace as well. TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); @@ -371,7 +395,7 @@ void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) { DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr); if (thr->ignore_sync) return; - SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true); + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); thr->fast_state.IncrementEpoch(); // Can't increment epoch w/o writing to the trace as well. TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); @@ -404,7 +428,7 @@ void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { if (thr->ignore_sync) return; thr->clock.set(thr->fast_state.epoch()); - thr->clock.acquire(c); + thr->clock.acquire(&thr->clock_cache, c); StatInc(thr, StatSyncAcquire); } @@ -413,7 +437,7 @@ void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { return; thr->clock.set(thr->fast_state.epoch()); thr->fast_synch_epoch = thr->fast_state.epoch(); - thr->clock.release(c); + thr->clock.release(&thr->clock_cache, c); StatInc(thr, StatSyncRelease); } @@ -422,7 +446,7 @@ void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) { return; thr->clock.set(thr->fast_state.epoch()); thr->fast_synch_epoch = thr->fast_state.epoch(); - thr->clock.ReleaseStore(c); + thr->clock.ReleaseStore(&thr->clock_cache, c); StatInc(thr, StatSyncRelease); } @@ -431,7 +455,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { return; thr->clock.set(thr->fast_state.epoch()); thr->fast_synch_epoch = thr->fast_state.epoch(); - thr->clock.acq_rel(c); + thr->clock.acq_rel(&thr->clock_cache, c); StatInc(thr, StatSyncAcquire); StatInc(thr, StatSyncRelease); } @@ -446,7 +470,7 @@ void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) { rep.AddUniqueTid((int)r->loop[i].thr_ctx); rep.AddThread((int)r->loop[i].thr_ctx); } - StackTrace stacks[2 * DDReport::kMaxLoopSize]; + InternalScopedBuffer<StackTrace> stacks(2 * DDReport::kMaxLoopSize); uptr dummy_pc = 0x42; for (int i = 0; i < r->n; i++) { uptr size; @@ -460,12 +484,10 @@ void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) { // but we should still produce some stack trace in the report. stacks[i].Init(&dummy_pc, 1); } - rep.AddStack(&stacks[i]); + rep.AddStack(&stacks[i], true); } } - // FIXME: use all stacks for suppressions, not just the second stack of the - // first edge. - OutputReport(ctx, rep, rep.GetReport()->stacks[0]); + OutputReport(thr, rep); } } // namespace __tsan |