1//===-- tsan_rtl_thread.cc ------------------------------------------------===// 2// 3// This file is distributed under the University of Illinois Open Source 4// License. See LICENSE.TXT for details. 5// 6//===----------------------------------------------------------------------===// 7// 8// This file is a part of ThreadSanitizer (TSan), a race detector. 9// 10//===----------------------------------------------------------------------===// 11 12#include "sanitizer_common/sanitizer_placement_new.h" 13#include "tsan_rtl.h" 14#include "tsan_mman.h" 15#include "tsan_platform.h" 16#include "tsan_report.h" 17#include "tsan_sync.h" 18 19namespace __tsan { 20 21// ThreadContext implementation. 22 23ThreadContext::ThreadContext(int tid) 24 : ThreadContextBase(tid) 25 , thr() 26 , sync() 27 , epoch0() 28 , epoch1() { 29} 30 31#ifndef TSAN_GO 32ThreadContext::~ThreadContext() { 33} 34#endif 35 36void ThreadContext::OnDead() { 37 CHECK_EQ(sync.size(), 0); 38} 39 40void ThreadContext::OnJoined(void *arg) { 41 ThreadState *caller_thr = static_cast<ThreadState *>(arg); 42 AcquireImpl(caller_thr, 0, &sync); 43 sync.Reset(&caller_thr->clock_cache); 44} 45 46struct OnCreatedArgs { 47 ThreadState *thr; 48 uptr pc; 49}; 50 51void ThreadContext::OnCreated(void *arg) { 52 thr = 0; 53 if (tid == 0) 54 return; 55 OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg); 56 args->thr->fast_state.IncrementEpoch(); 57 // Can't increment epoch w/o writing to the trace as well. 58 TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0); 59 ReleaseImpl(args->thr, 0, &sync); 60 creation_stack_id = CurrentStackId(args->thr, args->pc); 61 if (reuse_count == 0) 62 StatInc(args->thr, StatThreadMaxTid); 63} 64 65void ThreadContext::OnReset() { 66 CHECK_EQ(sync.size(), 0); 67 FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event)); 68 //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace)); 69} 70 71void ThreadContext::OnDetached(void *arg) { 72 ThreadState *thr1 = static_cast<ThreadState*>(arg); 73 sync.Reset(&thr1->clock_cache); 74} 75 76struct OnStartedArgs { 77 ThreadState *thr; 78 uptr stk_addr; 79 uptr stk_size; 80 uptr tls_addr; 81 uptr tls_size; 82}; 83 84void ThreadContext::OnStarted(void *arg) { 85 OnStartedArgs *args = static_cast<OnStartedArgs*>(arg); 86 thr = args->thr; 87 // RoundUp so that one trace part does not contain events 88 // from different threads. 89 epoch0 = RoundUp(epoch1 + 1, kTracePartSize); 90 epoch1 = (u64)-1; 91 new(thr) ThreadState(ctx, tid, unique_id, epoch0, reuse_count, 92 args->stk_addr, args->stk_size, args->tls_addr, args->tls_size); 93#ifndef TSAN_GO 94 thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0]; 95 thr->shadow_stack_pos = thr->shadow_stack; 96 thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize; 97#else 98 // Setup dynamic shadow stack. 99 const int kInitStackSize = 8; 100 thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack, 101 kInitStackSize * sizeof(uptr)); 102 thr->shadow_stack_pos = thr->shadow_stack; 103 thr->shadow_stack_end = thr->shadow_stack + kInitStackSize; 104#endif 105#ifndef TSAN_GO 106 AllocatorThreadStart(thr); 107#endif 108 if (common_flags()->detect_deadlocks) { 109 thr->dd_pt = ctx->dd->CreatePhysicalThread(); 110 thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id); 111 } 112 thr->fast_state.SetHistorySize(flags()->history_size); 113 // Commit switch to the new part of the trace. 114 // TraceAddEvent will reset stack0/mset0 in the new part for us. 115 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 116 117 thr->fast_synch_epoch = epoch0; 118 AcquireImpl(thr, 0, &sync); 119 StatInc(thr, StatSyncAcquire); 120 sync.Reset(&thr->clock_cache); 121 DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx " 122 "tls_addr=%zx tls_size=%zx\n", 123 tid, (uptr)epoch0, args->stk_addr, args->stk_size, 124 args->tls_addr, args->tls_size); 125} 126 127void ThreadContext::OnFinished() { 128 if (!detached) { 129 thr->fast_state.IncrementEpoch(); 130 // Can't increment epoch w/o writing to the trace as well. 131 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 132 ReleaseImpl(thr, 0, &sync); 133 } 134 epoch1 = thr->fast_state.epoch(); 135 136 if (common_flags()->detect_deadlocks) { 137 ctx->dd->DestroyPhysicalThread(thr->dd_pt); 138 ctx->dd->DestroyLogicalThread(thr->dd_lt); 139 } 140 ctx->clock_alloc.FlushCache(&thr->clock_cache); 141 ctx->metamap.OnThreadIdle(thr); 142#ifndef TSAN_GO 143 AllocatorThreadFinish(thr); 144#endif 145 thr->~ThreadState(); 146 StatAggregate(ctx->stat, thr->stat); 147 thr = 0; 148} 149 150#ifndef TSAN_GO 151struct ThreadLeak { 152 ThreadContext *tctx; 153 int count; 154}; 155 156static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) { 157 Vector<ThreadLeak> &leaks = *(Vector<ThreadLeak>*)arg; 158 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); 159 if (tctx->detached || tctx->status != ThreadStatusFinished) 160 return; 161 for (uptr i = 0; i < leaks.Size(); i++) { 162 if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) { 163 leaks[i].count++; 164 return; 165 } 166 } 167 ThreadLeak leak = {tctx, 1}; 168 leaks.PushBack(leak); 169} 170#endif 171 172#ifndef TSAN_GO 173static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) { 174 if (tctx->tid == 0) { 175 Printf("ThreadSanitizer: main thread finished with ignores enabled\n"); 176 } else { 177 Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled," 178 " created at:\n", tctx->tid, tctx->name); 179 PrintStack(SymbolizeStackId(tctx->creation_stack_id)); 180 } 181 Printf(" One of the following ignores was not ended" 182 " (in order of probability)\n"); 183 for (uptr i = 0; i < set->Size(); i++) { 184 Printf(" Ignore was enabled at:\n"); 185 PrintStack(SymbolizeStackId(set->At(i))); 186 } 187 Die(); 188} 189 190static void ThreadCheckIgnore(ThreadState *thr) { 191 if (ctx->after_multithreaded_fork) 192 return; 193 if (thr->ignore_reads_and_writes) 194 ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set); 195 if (thr->ignore_sync) 196 ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set); 197} 198#else 199static void ThreadCheckIgnore(ThreadState *thr) {} 200#endif 201 202void ThreadFinalize(ThreadState *thr) { 203 ThreadCheckIgnore(thr); 204#ifndef TSAN_GO 205 if (!flags()->report_thread_leaks) 206 return; 207 ThreadRegistryLock l(ctx->thread_registry); 208 Vector<ThreadLeak> leaks(MBlockScopedBuf); 209 ctx->thread_registry->RunCallbackForEachThreadLocked( 210 MaybeReportThreadLeak, &leaks); 211 for (uptr i = 0; i < leaks.Size(); i++) { 212 ScopedReport rep(ReportTypeThreadLeak); 213 rep.AddThread(leaks[i].tctx, true); 214 rep.SetCount(leaks[i].count); 215 OutputReport(thr, rep); 216 } 217#endif 218} 219 220int ThreadCount(ThreadState *thr) { 221 uptr result; 222 ctx->thread_registry->GetNumberOfThreads(0, 0, &result); 223 return (int)result; 224} 225 226int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) { 227 StatInc(thr, StatThreadCreate); 228 OnCreatedArgs args = { thr, pc }; 229 int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args); 230 DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid); 231 StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads()); 232 return tid; 233} 234 235void ThreadStart(ThreadState *thr, int tid, uptr os_id) { 236 uptr stk_addr = 0; 237 uptr stk_size = 0; 238 uptr tls_addr = 0; 239 uptr tls_size = 0; 240 GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size); 241 242 if (tid) { 243 if (stk_addr && stk_size) 244 MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size); 245 246 if (tls_addr && tls_size) { 247 // Check that the thr object is in tls; 248 const uptr thr_beg = (uptr)thr; 249 const uptr thr_end = (uptr)thr + sizeof(*thr); 250 CHECK_GE(thr_beg, tls_addr); 251 CHECK_LE(thr_beg, tls_addr + tls_size); 252 CHECK_GE(thr_end, tls_addr); 253 CHECK_LE(thr_end, tls_addr + tls_size); 254 // Since the thr object is huge, skip it. 255 MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr); 256 MemoryRangeImitateWrite(thr, /*pc=*/ 2, 257 thr_end, tls_addr + tls_size - thr_end); 258 } 259 } 260 261 ThreadRegistry *tr = ctx->thread_registry; 262 OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size }; 263 tr->StartThread(tid, os_id, &args); 264 265 tr->Lock(); 266 thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid); 267 tr->Unlock(); 268 269#ifndef TSAN_GO 270 if (ctx->after_multithreaded_fork) { 271 thr->ignore_interceptors++; 272 ThreadIgnoreBegin(thr, 0); 273 ThreadIgnoreSyncBegin(thr, 0); 274 } 275#endif 276} 277 278void ThreadFinish(ThreadState *thr) { 279 ThreadCheckIgnore(thr); 280 StatInc(thr, StatThreadFinish); 281 if (thr->stk_addr && thr->stk_size) 282 DontNeedShadowFor(thr->stk_addr, thr->stk_size); 283 if (thr->tls_addr && thr->tls_size) 284 DontNeedShadowFor(thr->tls_addr, thr->tls_size); 285 thr->is_dead = true; 286 ctx->thread_registry->FinishThread(thr->tid); 287} 288 289static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { 290 uptr uid = (uptr)arg; 291 if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { 292 tctx->user_id = 0; 293 return true; 294 } 295 return false; 296} 297 298int ThreadTid(ThreadState *thr, uptr pc, uptr uid) { 299 int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid); 300 DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res); 301 return res; 302} 303 304void ThreadJoin(ThreadState *thr, uptr pc, int tid) { 305 CHECK_GT(tid, 0); 306 CHECK_LT(tid, kMaxTid); 307 DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid); 308 ctx->thread_registry->JoinThread(tid, thr); 309} 310 311void ThreadDetach(ThreadState *thr, uptr pc, int tid) { 312 CHECK_GT(tid, 0); 313 CHECK_LT(tid, kMaxTid); 314 ctx->thread_registry->DetachThread(tid, thr); 315} 316 317void ThreadSetName(ThreadState *thr, const char *name) { 318 ctx->thread_registry->SetThreadName(thr->tid, name); 319} 320 321void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, 322 uptr size, bool is_write) { 323 if (size == 0) 324 return; 325 326 u64 *shadow_mem = (u64*)MemToShadow(addr); 327 DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n", 328 thr->tid, (void*)pc, (void*)addr, 329 (int)size, is_write); 330 331#if TSAN_DEBUG 332 if (!IsAppMem(addr)) { 333 Printf("Access to non app mem %zx\n", addr); 334 DCHECK(IsAppMem(addr)); 335 } 336 if (!IsAppMem(addr + size - 1)) { 337 Printf("Access to non app mem %zx\n", addr + size - 1); 338 DCHECK(IsAppMem(addr + size - 1)); 339 } 340 if (!IsShadowMem((uptr)shadow_mem)) { 341 Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr); 342 DCHECK(IsShadowMem((uptr)shadow_mem)); 343 } 344 if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) { 345 Printf("Bad shadow addr %p (%zx)\n", 346 shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1); 347 DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))); 348 } 349#endif 350 351 StatInc(thr, StatMopRange); 352 353 if (*shadow_mem == kShadowRodata) { 354 // Access to .rodata section, no races here. 355 // Measurements show that it can be 10-20% of all memory accesses. 356 StatInc(thr, StatMopRangeRodata); 357 return; 358 } 359 360 FastState fast_state = thr->fast_state; 361 if (fast_state.GetIgnoreBit()) 362 return; 363 364 fast_state.IncrementEpoch(); 365 thr->fast_state = fast_state; 366 TraceAddEvent(thr, fast_state, EventTypeMop, pc); 367 368 bool unaligned = (addr % kShadowCell) != 0; 369 370 // Handle unaligned beginning, if any. 371 for (; addr % kShadowCell && size; addr++, size--) { 372 int const kAccessSizeLog = 0; 373 Shadow cur(fast_state); 374 cur.SetWrite(is_write); 375 cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog); 376 MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, 377 shadow_mem, cur); 378 } 379 if (unaligned) 380 shadow_mem += kShadowCnt; 381 // Handle middle part, if any. 382 for (; size >= kShadowCell; addr += kShadowCell, size -= kShadowCell) { 383 int const kAccessSizeLog = 3; 384 Shadow cur(fast_state); 385 cur.SetWrite(is_write); 386 cur.SetAddr0AndSizeLog(0, kAccessSizeLog); 387 MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, 388 shadow_mem, cur); 389 shadow_mem += kShadowCnt; 390 } 391 // Handle ending, if any. 392 for (; size; addr++, size--) { 393 int const kAccessSizeLog = 0; 394 Shadow cur(fast_state); 395 cur.SetWrite(is_write); 396 cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog); 397 MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, 398 shadow_mem, cur); 399 } 400} 401 402} // namespace __tsan 403