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