Home | History | Annotate | Download | only in rtl
      1 //===-- tsan_rtl_mutex.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 
     14 #include <sanitizer_common/sanitizer_deadlock_detector_interface.h>
     15 #include <sanitizer_common/sanitizer_stackdepot.h>
     16 
     17 #include "tsan_rtl.h"
     18 #include "tsan_flags.h"
     19 #include "tsan_sync.h"
     20 #include "tsan_report.h"
     21 #include "tsan_symbolize.h"
     22 #include "tsan_platform.h"
     23 
     24 namespace __tsan {
     25 
     26 void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r);
     27 
     28 struct Callback : DDCallback {
     29   ThreadState *thr;
     30   uptr pc;
     31 
     32   Callback(ThreadState *thr, uptr pc)
     33       : thr(thr)
     34       , pc(pc) {
     35     DDCallback::pt = thr->proc()->dd_pt;
     36     DDCallback::lt = thr->dd_lt;
     37   }
     38 
     39   u32 Unwind() override { return CurrentStackId(thr, pc); }
     40   int UniqueTid() override { return thr->unique_id; }
     41 };
     42 
     43 void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) {
     44   Callback cb(thr, pc);
     45   ctx->dd->MutexInit(&cb, &s->dd);
     46   s->dd.ctx = s->GetId();
     47 }
     48 
     49 static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
     50     uptr addr, u64 mid) {
     51   // In Go, these misuses are either impossible, or detected by std lib,
     52   // or false positives (e.g. unlock in a different thread).
     53   if (kGoMode)
     54     return;
     55   ThreadRegistryLock l(ctx->thread_registry);
     56   ScopedReport rep(typ);
     57   rep.AddMutex(mid);
     58   VarSizeStackTrace trace;
     59   ObtainCurrentStack(thr, pc, &trace);
     60   rep.AddStack(trace, true);
     61   rep.AddLocation(addr, 1);
     62   OutputReport(thr, rep);
     63 }
     64 
     65 void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
     66                  bool rw, bool recursive, bool linker_init) {
     67   DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
     68   StatInc(thr, StatMutexCreate);
     69   if (!linker_init && IsAppMem(addr)) {
     70     CHECK(!thr->is_freeing);
     71     thr->is_freeing = true;
     72     MemoryWrite(thr, pc, addr, kSizeLog1);
     73     thr->is_freeing = false;
     74   }
     75   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
     76   s->is_rw = rw;
     77   s->is_recursive = recursive;
     78   s->is_linker_init = linker_init;
     79   if (kCppMode && s->creation_stack_id == 0)
     80     s->creation_stack_id = CurrentStackId(thr, pc);
     81   s->mtx.Unlock();
     82 }
     83 
     84 void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
     85   DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
     86   StatInc(thr, StatMutexDestroy);
     87   SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true);
     88   if (s == 0)
     89     return;
     90   if (s->is_linker_init) {
     91     // Destroy is no-op for linker-initialized mutexes.
     92     s->mtx.Unlock();
     93     return;
     94   }
     95   if (common_flags()->detect_deadlocks) {
     96     Callback cb(thr, pc);
     97     ctx->dd->MutexDestroy(&cb, &s->dd);
     98     ctx->dd->MutexInit(&cb, &s->dd);
     99   }
    100   bool unlock_locked = false;
    101   if (flags()->report_destroy_locked
    102       && s->owner_tid != SyncVar::kInvalidTid
    103       && !s->is_broken) {
    104     s->is_broken = true;
    105     unlock_locked = true;
    106   }
    107   u64 mid = s->GetId();
    108   u32 last_lock = s->last_lock;
    109   if (!unlock_locked)
    110     s->Reset(thr->proc());  // must not reset it before the report is printed
    111   s->mtx.Unlock();
    112   if (unlock_locked) {
    113     ThreadRegistryLock l(ctx->thread_registry);
    114     ScopedReport rep(ReportTypeMutexDestroyLocked);
    115     rep.AddMutex(mid);
    116     VarSizeStackTrace trace;
    117     ObtainCurrentStack(thr, pc, &trace);
    118     rep.AddStack(trace);
    119     FastState last(last_lock);
    120     RestoreStack(last.tid(), last.epoch(), &trace, 0);
    121     rep.AddStack(trace, true);
    122     rep.AddLocation(addr, 1);
    123     OutputReport(thr, rep);
    124 
    125     SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true);
    126     if (s != 0) {
    127       s->Reset(thr->proc());
    128       s->mtx.Unlock();
    129     }
    130   }
    131   thr->mset.Remove(mid);
    132   // Imitate a memory write to catch unlock-destroy races.
    133   // Do this outside of sync mutex, because it can report a race which locks
    134   // sync mutexes.
    135   if (IsAppMem(addr)) {
    136     CHECK(!thr->is_freeing);
    137     thr->is_freeing = true;
    138     MemoryWrite(thr, pc, addr, kSizeLog1);
    139     thr->is_freeing = false;
    140   }
    141   // s will be destroyed and freed in MetaMap::FreeBlock.
    142 }
    143 
    144 void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
    145   DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
    146   CHECK_GT(rec, 0);
    147   if (IsAppMem(addr))
    148     MemoryReadAtomic(thr, pc, addr, kSizeLog1);
    149   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
    150   thr->fast_state.IncrementEpoch();
    151   TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
    152   bool report_double_lock = false;
    153   if (s->owner_tid == SyncVar::kInvalidTid) {
    154     CHECK_EQ(s->recursion, 0);
    155     s->owner_tid = thr->tid;
    156     s->last_lock = thr->fast_state.raw();
    157   } else if (s->owner_tid == thr->tid) {
    158     CHECK_GT(s->recursion, 0);
    159   } else if (flags()->report_mutex_bugs && !s->is_broken) {
    160     s->is_broken = true;
    161     report_double_lock = true;
    162   }
    163   if (s->recursion == 0) {
    164     StatInc(thr, StatMutexLock);
    165     AcquireImpl(thr, pc, &s->clock);
    166     AcquireImpl(thr, pc, &s->read_clock);
    167   } else if (!s->is_recursive) {
    168     StatInc(thr, StatMutexRecLock);
    169   }
    170   s->recursion += rec;
    171   thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
    172   if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) {
    173     Callback cb(thr, pc);
    174     if (!try_lock)
    175       ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
    176     ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock);
    177   }
    178   u64 mid = s->GetId();
    179   s->mtx.Unlock();
    180   // Can't touch s after this point.
    181   if (report_double_lock)
    182     ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid);
    183   if (common_flags()->detect_deadlocks) {
    184     Callback cb(thr, pc);
    185     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
    186   }
    187 }
    188 
    189 int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
    190   DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
    191   if (IsAppMem(addr))
    192     MemoryReadAtomic(thr, pc, addr, kSizeLog1);
    193   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
    194   thr->fast_state.IncrementEpoch();
    195   TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
    196   int rec = 0;
    197   bool report_bad_unlock = false;
    198   if (kCppMode && (s->recursion == 0 || s->owner_tid != thr->tid)) {
    199     if (flags()->report_mutex_bugs && !s->is_broken) {
    200       s->is_broken = true;
    201       report_bad_unlock = true;
    202     }
    203   } else {
    204     rec = all ? s->recursion : 1;
    205     s->recursion -= rec;
    206     if (s->recursion == 0) {
    207       StatInc(thr, StatMutexUnlock);
    208       s->owner_tid = SyncVar::kInvalidTid;
    209       ReleaseStoreImpl(thr, pc, &s->clock);
    210     } else {
    211       StatInc(thr, StatMutexRecUnlock);
    212     }
    213   }
    214   thr->mset.Del(s->GetId(), true);
    215   if (common_flags()->detect_deadlocks && s->recursion == 0 &&
    216       !report_bad_unlock) {
    217     Callback cb(thr, pc);
    218     ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true);
    219   }
    220   u64 mid = s->GetId();
    221   s->mtx.Unlock();
    222   // Can't touch s after this point.
    223   if (report_bad_unlock)
    224     ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
    225   if (common_flags()->detect_deadlocks && !report_bad_unlock) {
    226     Callback cb(thr, pc);
    227     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
    228   }
    229   return rec;
    230 }
    231 
    232 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) {
    233   DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
    234   StatInc(thr, StatMutexReadLock);
    235   if (IsAppMem(addr))
    236     MemoryReadAtomic(thr, pc, addr, kSizeLog1);
    237   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
    238   thr->fast_state.IncrementEpoch();
    239   TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
    240   bool report_bad_lock = false;
    241   if (s->owner_tid != SyncVar::kInvalidTid) {
    242     if (flags()->report_mutex_bugs && !s->is_broken) {
    243       s->is_broken = true;
    244       report_bad_lock = true;
    245     }
    246   }
    247   AcquireImpl(thr, pc, &s->clock);
    248   s->last_lock = thr->fast_state.raw();
    249   thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
    250   if (common_flags()->detect_deadlocks && s->recursion == 0) {
    251     Callback cb(thr, pc);
    252     if (!trylock)
    253       ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
    254     ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock);
    255   }
    256   u64 mid = s->GetId();
    257   s->mtx.ReadUnlock();
    258   // Can't touch s after this point.
    259   if (report_bad_lock)
    260     ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid);
    261   if (common_flags()->detect_deadlocks) {
    262     Callback cb(thr, pc);
    263     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
    264   }
    265 }
    266 
    267 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
    268   DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
    269   StatInc(thr, StatMutexReadUnlock);
    270   if (IsAppMem(addr))
    271     MemoryReadAtomic(thr, pc, addr, kSizeLog1);
    272   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
    273   thr->fast_state.IncrementEpoch();
    274   TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
    275   bool report_bad_unlock = false;
    276   if (s->owner_tid != SyncVar::kInvalidTid) {
    277     if (flags()->report_mutex_bugs && !s->is_broken) {
    278       s->is_broken = true;
    279       report_bad_unlock = true;
    280     }
    281   }
    282   ReleaseImpl(thr, pc, &s->read_clock);
    283   if (common_flags()->detect_deadlocks && s->recursion == 0) {
    284     Callback cb(thr, pc);
    285     ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false);
    286   }
    287   u64 mid = s->GetId();
    288   s->mtx.Unlock();
    289   // Can't touch s after this point.
    290   thr->mset.Del(mid, false);
    291   if (report_bad_unlock)
    292     ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid);
    293   if (common_flags()->detect_deadlocks) {
    294     Callback cb(thr, pc);
    295     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
    296   }
    297 }
    298 
    299 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
    300   DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
    301   if (IsAppMem(addr))
    302     MemoryReadAtomic(thr, pc, addr, kSizeLog1);
    303   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
    304   bool write = true;
    305   bool report_bad_unlock = false;
    306   if (s->owner_tid == SyncVar::kInvalidTid) {
    307     // Seems to be read unlock.
    308     write = false;
    309     StatInc(thr, StatMutexReadUnlock);
    310     thr->fast_state.IncrementEpoch();
    311     TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
    312     ReleaseImpl(thr, pc, &s->read_clock);
    313   } else if (s->owner_tid == thr->tid) {
    314     // Seems to be write unlock.
    315     thr->fast_state.IncrementEpoch();
    316     TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
    317     CHECK_GT(s->recursion, 0);
    318     s->recursion--;
    319     if (s->recursion == 0) {
    320       StatInc(thr, StatMutexUnlock);
    321       s->owner_tid = SyncVar::kInvalidTid;
    322       ReleaseImpl(thr, pc, &s->clock);
    323     } else {
    324       StatInc(thr, StatMutexRecUnlock);
    325     }
    326   } else if (!s->is_broken) {
    327     s->is_broken = true;
    328     report_bad_unlock = true;
    329   }
    330   thr->mset.Del(s->GetId(), write);
    331   if (common_flags()->detect_deadlocks && s->recursion == 0) {
    332     Callback cb(thr, pc);
    333     ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write);
    334   }
    335   u64 mid = s->GetId();
    336   s->mtx.Unlock();
    337   // Can't touch s after this point.
    338   if (report_bad_unlock)
    339     ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
    340   if (common_flags()->detect_deadlocks) {
    341     Callback cb(thr, pc);
    342     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
    343   }
    344 }
    345 
    346 void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
    347   DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
    348   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
    349   s->owner_tid = SyncVar::kInvalidTid;
    350   s->recursion = 0;
    351   s->mtx.Unlock();
    352 }
    353 
    354 void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr) {
    355   DPrintf("#%d: MutexInvalidAccess %zx\n", thr->tid, addr);
    356   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
    357   u64 mid = s->GetId();
    358   s->mtx.Unlock();
    359   ReportMutexMisuse(thr, pc, ReportTypeMutexInvalidAccess, addr, mid);
    360 }
    361 
    362 void Acquire(ThreadState *thr, uptr pc, uptr addr) {
    363   DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
    364   if (thr->ignore_sync)
    365     return;
    366   SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, false);
    367   if (!s)
    368     return;
    369   AcquireImpl(thr, pc, &s->clock);
    370   s->mtx.ReadUnlock();
    371 }
    372 
    373 static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
    374   ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
    375   ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
    376   if (tctx->status == ThreadStatusRunning)
    377     thr->clock.set(tctx->tid, tctx->thr->fast_state.epoch());
    378   else
    379     thr->clock.set(tctx->tid, tctx->epoch1);
    380 }
    381 
    382 void AcquireGlobal(ThreadState *thr, uptr pc) {
    383   DPrintf("#%d: AcquireGlobal\n", thr->tid);
    384   if (thr->ignore_sync)
    385     return;
    386   ThreadRegistryLock l(ctx->thread_registry);
    387   ctx->thread_registry->RunCallbackForEachThreadLocked(
    388       UpdateClockCallback, thr);
    389 }
    390 
    391 void Release(ThreadState *thr, uptr pc, uptr addr) {
    392   DPrintf("#%d: Release %zx\n", thr->tid, addr);
    393   if (thr->ignore_sync)
    394     return;
    395   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
    396   thr->fast_state.IncrementEpoch();
    397   // Can't increment epoch w/o writing to the trace as well.
    398   TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
    399   ReleaseImpl(thr, pc, &s->clock);
    400   s->mtx.Unlock();
    401 }
    402 
    403 void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
    404   DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
    405   if (thr->ignore_sync)
    406     return;
    407   SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
    408   thr->fast_state.IncrementEpoch();
    409   // Can't increment epoch w/o writing to the trace as well.
    410   TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
    411   ReleaseStoreImpl(thr, pc, &s->clock);
    412   s->mtx.Unlock();
    413 }
    414 
    415 #ifndef SANITIZER_GO
    416 static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) {
    417   ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
    418   ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
    419   if (tctx->status == ThreadStatusRunning)
    420     thr->last_sleep_clock.set(tctx->tid, tctx->thr->fast_state.epoch());
    421   else
    422     thr->last_sleep_clock.set(tctx->tid, tctx->epoch1);
    423 }
    424 
    425 void AfterSleep(ThreadState *thr, uptr pc) {
    426   DPrintf("#%d: AfterSleep %zx\n", thr->tid);
    427   if (thr->ignore_sync)
    428     return;
    429   thr->last_sleep_stack_id = CurrentStackId(thr, pc);
    430   ThreadRegistryLock l(ctx->thread_registry);
    431   ctx->thread_registry->RunCallbackForEachThreadLocked(
    432       UpdateSleepClockCallback, thr);
    433 }
    434 #endif
    435 
    436 void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
    437   if (thr->ignore_sync)
    438     return;
    439   thr->clock.set(thr->fast_state.epoch());
    440   thr->clock.acquire(&thr->proc()->clock_cache, c);
    441   StatInc(thr, StatSyncAcquire);
    442 }
    443 
    444 void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
    445   if (thr->ignore_sync)
    446     return;
    447   thr->clock.set(thr->fast_state.epoch());
    448   thr->fast_synch_epoch = thr->fast_state.epoch();
    449   thr->clock.release(&thr->proc()->clock_cache, c);
    450   StatInc(thr, StatSyncRelease);
    451 }
    452 
    453 void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) {
    454   if (thr->ignore_sync)
    455     return;
    456   thr->clock.set(thr->fast_state.epoch());
    457   thr->fast_synch_epoch = thr->fast_state.epoch();
    458   thr->clock.ReleaseStore(&thr->proc()->clock_cache, c);
    459   StatInc(thr, StatSyncRelease);
    460 }
    461 
    462 void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
    463   if (thr->ignore_sync)
    464     return;
    465   thr->clock.set(thr->fast_state.epoch());
    466   thr->fast_synch_epoch = thr->fast_state.epoch();
    467   thr->clock.acq_rel(&thr->proc()->clock_cache, c);
    468   StatInc(thr, StatSyncAcquire);
    469   StatInc(thr, StatSyncRelease);
    470 }
    471 
    472 void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
    473   if (r == 0)
    474     return;
    475   ThreadRegistryLock l(ctx->thread_registry);
    476   ScopedReport rep(ReportTypeDeadlock);
    477   for (int i = 0; i < r->n; i++) {
    478     rep.AddMutex(r->loop[i].mtx_ctx0);
    479     rep.AddUniqueTid((int)r->loop[i].thr_ctx);
    480     rep.AddThread((int)r->loop[i].thr_ctx);
    481   }
    482   uptr dummy_pc = 0x42;
    483   for (int i = 0; i < r->n; i++) {
    484     for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
    485       u32 stk = r->loop[i].stk[j];
    486       if (stk && stk != 0xffffffff) {
    487         rep.AddStack(StackDepotGet(stk), true);
    488       } else {
    489         // Sometimes we fail to extract the stack trace (FIXME: investigate),
    490         // but we should still produce some stack trace in the report.
    491         rep.AddStack(StackTrace(&dummy_pc, 1), true);
    492       }
    493     }
    494   }
    495   OutputReport(thr, rep);
    496 }
    497 
    498 }  // namespace __tsan
    499