1//===-- tsan_rtl_report.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_libc.h" 15#include "sanitizer_common/sanitizer_placement_new.h" 16#include "sanitizer_common/sanitizer_stackdepot.h" 17#include "sanitizer_common/sanitizer_common.h" 18#include "sanitizer_common/sanitizer_stacktrace.h" 19#include "tsan_platform.h" 20#include "tsan_rtl.h" 21#include "tsan_suppressions.h" 22#include "tsan_symbolize.h" 23#include "tsan_report.h" 24#include "tsan_sync.h" 25#include "tsan_mman.h" 26#include "tsan_flags.h" 27#include "tsan_fd.h" 28 29namespace __tsan { 30 31using namespace __sanitizer; // NOLINT 32 33static ReportStack *SymbolizeStack(StackTrace trace); 34 35void TsanCheckFailed(const char *file, int line, const char *cond, 36 u64 v1, u64 v2) { 37 // There is high probability that interceptors will check-fail as well, 38 // on the other hand there is no sense in processing interceptors 39 // since we are going to die soon. 40 ScopedIgnoreInterceptors ignore; 41 Printf("FATAL: ThreadSanitizer CHECK failed: " 42 "%s:%d \"%s\" (0x%zx, 0x%zx)\n", 43 file, line, cond, (uptr)v1, (uptr)v2); 44 PrintCurrentStackSlow(StackTrace::GetCurrentPc()); 45 Die(); 46} 47 48// Can be overriden by an application/test to intercept reports. 49#ifdef TSAN_EXTERNAL_HOOKS 50bool OnReport(const ReportDesc *rep, bool suppressed); 51#else 52SANITIZER_WEAK_CXX_DEFAULT_IMPL 53bool OnReport(const ReportDesc *rep, bool suppressed) { 54 (void)rep; 55 return suppressed; 56} 57#endif 58 59static void StackStripMain(SymbolizedStack *frames) { 60 SymbolizedStack *last_frame = nullptr; 61 SymbolizedStack *last_frame2 = nullptr; 62 for (SymbolizedStack *cur = frames; cur; cur = cur->next) { 63 last_frame2 = last_frame; 64 last_frame = cur; 65 } 66 67 if (last_frame2 == 0) 68 return; 69#ifndef SANITIZER_GO 70 const char *last = last_frame->info.function; 71 const char *last2 = last_frame2->info.function; 72 // Strip frame above 'main' 73 if (last2 && 0 == internal_strcmp(last2, "main")) { 74 last_frame->ClearAll(); 75 last_frame2->next = nullptr; 76 // Strip our internal thread start routine. 77 } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) { 78 last_frame->ClearAll(); 79 last_frame2->next = nullptr; 80 // Strip global ctors init. 81 } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) { 82 last_frame->ClearAll(); 83 last_frame2->next = nullptr; 84 // If both are 0, then we probably just failed to symbolize. 85 } else if (last || last2) { 86 // Ensure that we recovered stack completely. Trimmed stack 87 // can actually happen if we do not instrument some code, 88 // so it's only a debug print. However we must try hard to not miss it 89 // due to our fault. 90 DPrintf("Bottom stack frame is missed\n"); 91 } 92#else 93 // The last frame always point into runtime (gosched0, goexit0, runtime.main). 94 last_frame->ClearAll(); 95 last_frame2->next = nullptr; 96#endif 97} 98 99ReportStack *SymbolizeStackId(u32 stack_id) { 100 if (stack_id == 0) 101 return 0; 102 StackTrace stack = StackDepotGet(stack_id); 103 if (stack.trace == nullptr) 104 return nullptr; 105 return SymbolizeStack(stack); 106} 107 108static ReportStack *SymbolizeStack(StackTrace trace) { 109 if (trace.size == 0) 110 return 0; 111 SymbolizedStack *top = nullptr; 112 for (uptr si = 0; si < trace.size; si++) { 113 const uptr pc = trace.trace[si]; 114 uptr pc1 = pc; 115 // We obtain the return address, but we're interested in the previous 116 // instruction. 117 if ((pc & kExternalPCBit) == 0) 118 pc1 = StackTrace::GetPreviousInstructionPc(pc); 119 SymbolizedStack *ent = SymbolizeCode(pc1); 120 CHECK_NE(ent, 0); 121 SymbolizedStack *last = ent; 122 while (last->next) { 123 last->info.address = pc; // restore original pc for report 124 last = last->next; 125 } 126 last->info.address = pc; // restore original pc for report 127 last->next = top; 128 top = ent; 129 } 130 StackStripMain(top); 131 132 ReportStack *stack = ReportStack::New(); 133 stack->frames = top; 134 return stack; 135} 136 137ScopedReport::ScopedReport(ReportType typ) { 138 ctx->thread_registry->CheckLocked(); 139 void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc)); 140 rep_ = new(mem) ReportDesc; 141 rep_->typ = typ; 142 ctx->report_mtx.Lock(); 143 CommonSanitizerReportMutex.Lock(); 144} 145 146ScopedReport::~ScopedReport() { 147 CommonSanitizerReportMutex.Unlock(); 148 ctx->report_mtx.Unlock(); 149 DestroyAndFree(rep_); 150} 151 152void ScopedReport::AddStack(StackTrace stack, bool suppressable) { 153 ReportStack **rs = rep_->stacks.PushBack(); 154 *rs = SymbolizeStack(stack); 155 (*rs)->suppressable = suppressable; 156} 157 158void ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack, 159 const MutexSet *mset) { 160 void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop)); 161 ReportMop *mop = new(mem) ReportMop; 162 rep_->mops.PushBack(mop); 163 mop->tid = s.tid(); 164 mop->addr = addr + s.addr0(); 165 mop->size = s.size(); 166 mop->write = s.IsWrite(); 167 mop->atomic = s.IsAtomic(); 168 mop->stack = SymbolizeStack(stack); 169 if (mop->stack) 170 mop->stack->suppressable = true; 171 for (uptr i = 0; i < mset->Size(); i++) { 172 MutexSet::Desc d = mset->Get(i); 173 u64 mid = this->AddMutex(d.id); 174 ReportMopMutex mtx = {mid, d.write}; 175 mop->mset.PushBack(mtx); 176 } 177} 178 179void ScopedReport::AddUniqueTid(int unique_tid) { 180 rep_->unique_tids.PushBack(unique_tid); 181} 182 183void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) { 184 for (uptr i = 0; i < rep_->threads.Size(); i++) { 185 if ((u32)rep_->threads[i]->id == tctx->tid) 186 return; 187 } 188 void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread)); 189 ReportThread *rt = new(mem) ReportThread; 190 rep_->threads.PushBack(rt); 191 rt->id = tctx->tid; 192 rt->pid = tctx->os_id; 193 rt->running = (tctx->status == ThreadStatusRunning); 194 rt->name = internal_strdup(tctx->name); 195 rt->parent_tid = tctx->parent_tid; 196 rt->stack = 0; 197 rt->stack = SymbolizeStackId(tctx->creation_stack_id); 198 if (rt->stack) 199 rt->stack->suppressable = suppressable; 200} 201 202#ifndef SANITIZER_GO 203static bool FindThreadByUidLockedCallback(ThreadContextBase *tctx, void *arg) { 204 int unique_id = *(int *)arg; 205 return tctx->unique_id == (u32)unique_id; 206} 207 208static ThreadContext *FindThreadByUidLocked(int unique_id) { 209 ctx->thread_registry->CheckLocked(); 210 return static_cast<ThreadContext *>( 211 ctx->thread_registry->FindThreadContextLocked( 212 FindThreadByUidLockedCallback, &unique_id)); 213} 214 215static ThreadContext *FindThreadByTidLocked(int tid) { 216 ctx->thread_registry->CheckLocked(); 217 return static_cast<ThreadContext*>( 218 ctx->thread_registry->GetThreadLocked(tid)); 219} 220 221static bool IsInStackOrTls(ThreadContextBase *tctx_base, void *arg) { 222 uptr addr = (uptr)arg; 223 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); 224 if (tctx->status != ThreadStatusRunning) 225 return false; 226 ThreadState *thr = tctx->thr; 227 CHECK(thr); 228 return ((addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size) || 229 (addr >= thr->tls_addr && addr < thr->tls_addr + thr->tls_size)); 230} 231 232ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) { 233 ctx->thread_registry->CheckLocked(); 234 ThreadContext *tctx = static_cast<ThreadContext*>( 235 ctx->thread_registry->FindThreadContextLocked(IsInStackOrTls, 236 (void*)addr)); 237 if (!tctx) 238 return 0; 239 ThreadState *thr = tctx->thr; 240 CHECK(thr); 241 *is_stack = (addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size); 242 return tctx; 243} 244#endif 245 246void ScopedReport::AddThread(int unique_tid, bool suppressable) { 247#ifndef SANITIZER_GO 248 if (const ThreadContext *tctx = FindThreadByUidLocked(unique_tid)) 249 AddThread(tctx, suppressable); 250#endif 251} 252 253void ScopedReport::AddMutex(const SyncVar *s) { 254 for (uptr i = 0; i < rep_->mutexes.Size(); i++) { 255 if (rep_->mutexes[i]->id == s->uid) 256 return; 257 } 258 void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex)); 259 ReportMutex *rm = new(mem) ReportMutex; 260 rep_->mutexes.PushBack(rm); 261 rm->id = s->uid; 262 rm->addr = s->addr; 263 rm->destroyed = false; 264 rm->stack = SymbolizeStackId(s->creation_stack_id); 265} 266 267u64 ScopedReport::AddMutex(u64 id) { 268 u64 uid = 0; 269 u64 mid = id; 270 uptr addr = SyncVar::SplitId(id, &uid); 271 SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr); 272 // Check that the mutex is still alive. 273 // Another mutex can be created at the same address, 274 // so check uid as well. 275 if (s && s->CheckId(uid)) { 276 mid = s->uid; 277 AddMutex(s); 278 } else { 279 AddDeadMutex(id); 280 } 281 if (s) 282 s->mtx.Unlock(); 283 return mid; 284} 285 286void ScopedReport::AddDeadMutex(u64 id) { 287 for (uptr i = 0; i < rep_->mutexes.Size(); i++) { 288 if (rep_->mutexes[i]->id == id) 289 return; 290 } 291 void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex)); 292 ReportMutex *rm = new(mem) ReportMutex; 293 rep_->mutexes.PushBack(rm); 294 rm->id = id; 295 rm->addr = 0; 296 rm->destroyed = true; 297 rm->stack = 0; 298} 299 300void ScopedReport::AddLocation(uptr addr, uptr size) { 301 if (addr == 0) 302 return; 303#ifndef SANITIZER_GO 304 int fd = -1; 305 int creat_tid = -1; 306 u32 creat_stack = 0; 307 if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) { 308 ReportLocation *loc = ReportLocation::New(ReportLocationFD); 309 loc->fd = fd; 310 loc->tid = creat_tid; 311 loc->stack = SymbolizeStackId(creat_stack); 312 rep_->locs.PushBack(loc); 313 ThreadContext *tctx = FindThreadByUidLocked(creat_tid); 314 if (tctx) 315 AddThread(tctx); 316 return; 317 } 318 MBlock *b = 0; 319 Allocator *a = allocator(); 320 if (a->PointerIsMine((void*)addr)) { 321 void *block_begin = a->GetBlockBegin((void*)addr); 322 if (block_begin) 323 b = ctx->metamap.GetBlock((uptr)block_begin); 324 } 325 if (b != 0) { 326 ThreadContext *tctx = FindThreadByTidLocked(b->tid); 327 ReportLocation *loc = ReportLocation::New(ReportLocationHeap); 328 loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr); 329 loc->heap_chunk_size = b->siz; 330 loc->tid = tctx ? tctx->tid : b->tid; 331 loc->stack = SymbolizeStackId(b->stk); 332 rep_->locs.PushBack(loc); 333 if (tctx) 334 AddThread(tctx); 335 return; 336 } 337 bool is_stack = false; 338 if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) { 339 ReportLocation *loc = 340 ReportLocation::New(is_stack ? ReportLocationStack : ReportLocationTLS); 341 loc->tid = tctx->tid; 342 rep_->locs.PushBack(loc); 343 AddThread(tctx); 344 } 345 if (ReportLocation *loc = SymbolizeData(addr)) { 346 loc->suppressable = true; 347 rep_->locs.PushBack(loc); 348 return; 349 } 350#endif 351} 352 353#ifndef SANITIZER_GO 354void ScopedReport::AddSleep(u32 stack_id) { 355 rep_->sleep = SymbolizeStackId(stack_id); 356} 357#endif 358 359void ScopedReport::SetCount(int count) { 360 rep_->count = count; 361} 362 363const ReportDesc *ScopedReport::GetReport() const { 364 return rep_; 365} 366 367void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, 368 MutexSet *mset) { 369 // This function restores stack trace and mutex set for the thread/epoch. 370 // It does so by getting stack trace and mutex set at the beginning of 371 // trace part, and then replaying the trace till the given epoch. 372 Trace* trace = ThreadTrace(tid); 373 ReadLock l(&trace->mtx); 374 const int partidx = (epoch / kTracePartSize) % TraceParts(); 375 TraceHeader* hdr = &trace->headers[partidx]; 376 if (epoch < hdr->epoch0 || epoch >= hdr->epoch0 + kTracePartSize) 377 return; 378 CHECK_EQ(RoundDown(epoch, kTracePartSize), hdr->epoch0); 379 const u64 epoch0 = RoundDown(epoch, TraceSize()); 380 const u64 eend = epoch % TraceSize(); 381 const u64 ebegin = RoundDown(eend, kTracePartSize); 382 DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n", 383 tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx); 384 Vector<uptr> stack(MBlockReportStack); 385 stack.Resize(hdr->stack0.size + 64); 386 for (uptr i = 0; i < hdr->stack0.size; i++) { 387 stack[i] = hdr->stack0.trace[i]; 388 DPrintf2(" #%02zu: pc=%zx\n", i, stack[i]); 389 } 390 if (mset) 391 *mset = hdr->mset0; 392 uptr pos = hdr->stack0.size; 393 Event *events = (Event*)GetThreadTrace(tid); 394 for (uptr i = ebegin; i <= eend; i++) { 395 Event ev = events[i]; 396 EventType typ = (EventType)(ev >> 61); 397 uptr pc = (uptr)(ev & ((1ull << 61) - 1)); 398 DPrintf2(" %zu typ=%d pc=%zx\n", i, typ, pc); 399 if (typ == EventTypeMop) { 400 stack[pos] = pc; 401 } else if (typ == EventTypeFuncEnter) { 402 if (stack.Size() < pos + 2) 403 stack.Resize(pos + 2); 404 stack[pos++] = pc; 405 } else if (typ == EventTypeFuncExit) { 406 if (pos > 0) 407 pos--; 408 } 409 if (mset) { 410 if (typ == EventTypeLock) { 411 mset->Add(pc, true, epoch0 + i); 412 } else if (typ == EventTypeUnlock) { 413 mset->Del(pc, true); 414 } else if (typ == EventTypeRLock) { 415 mset->Add(pc, false, epoch0 + i); 416 } else if (typ == EventTypeRUnlock) { 417 mset->Del(pc, false); 418 } 419 } 420 for (uptr j = 0; j <= pos; j++) 421 DPrintf2(" #%zu: %zx\n", j, stack[j]); 422 } 423 if (pos == 0 && stack[0] == 0) 424 return; 425 pos++; 426 stk->Init(&stack[0], pos); 427} 428 429static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2], 430 uptr addr_min, uptr addr_max) { 431 bool equal_stack = false; 432 RacyStacks hash; 433 bool equal_address = false; 434 RacyAddress ra0 = {addr_min, addr_max}; 435 { 436 ReadLock lock(&ctx->racy_mtx); 437 if (flags()->suppress_equal_stacks) { 438 hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr)); 439 hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr)); 440 for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) { 441 if (hash == ctx->racy_stacks[i]) { 442 VPrintf(2, 443 "ThreadSanitizer: suppressing report as doubled (stack)\n"); 444 equal_stack = true; 445 break; 446 } 447 } 448 } 449 if (flags()->suppress_equal_addresses) { 450 for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) { 451 RacyAddress ra2 = ctx->racy_addresses[i]; 452 uptr maxbeg = max(ra0.addr_min, ra2.addr_min); 453 uptr minend = min(ra0.addr_max, ra2.addr_max); 454 if (maxbeg < minend) { 455 VPrintf(2, "ThreadSanitizer: suppressing report as doubled (addr)\n"); 456 equal_address = true; 457 break; 458 } 459 } 460 } 461 } 462 if (!equal_stack && !equal_address) 463 return false; 464 if (!equal_stack) { 465 Lock lock(&ctx->racy_mtx); 466 ctx->racy_stacks.PushBack(hash); 467 } 468 if (!equal_address) { 469 Lock lock(&ctx->racy_mtx); 470 ctx->racy_addresses.PushBack(ra0); 471 } 472 return true; 473} 474 475static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2], 476 uptr addr_min, uptr addr_max) { 477 Lock lock(&ctx->racy_mtx); 478 if (flags()->suppress_equal_stacks) { 479 RacyStacks hash; 480 hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr)); 481 hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr)); 482 ctx->racy_stacks.PushBack(hash); 483 } 484 if (flags()->suppress_equal_addresses) { 485 RacyAddress ra0 = {addr_min, addr_max}; 486 ctx->racy_addresses.PushBack(ra0); 487 } 488} 489 490bool OutputReport(ThreadState *thr, const ScopedReport &srep) { 491 if (!flags()->report_bugs) 492 return false; 493 atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime()); 494 const ReportDesc *rep = srep.GetReport(); 495 Suppression *supp = 0; 496 uptr pc_or_addr = 0; 497 for (uptr i = 0; pc_or_addr == 0 && i < rep->mops.Size(); i++) 498 pc_or_addr = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp); 499 for (uptr i = 0; pc_or_addr == 0 && i < rep->stacks.Size(); i++) 500 pc_or_addr = IsSuppressed(rep->typ, rep->stacks[i], &supp); 501 for (uptr i = 0; pc_or_addr == 0 && i < rep->threads.Size(); i++) 502 pc_or_addr = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp); 503 for (uptr i = 0; pc_or_addr == 0 && i < rep->locs.Size(); i++) 504 pc_or_addr = IsSuppressed(rep->typ, rep->locs[i], &supp); 505 if (pc_or_addr != 0) { 506 Lock lock(&ctx->fired_suppressions_mtx); 507 FiredSuppression s = {srep.GetReport()->typ, pc_or_addr, supp}; 508 ctx->fired_suppressions.push_back(s); 509 } 510 { 511 bool old_is_freeing = thr->is_freeing; 512 thr->is_freeing = false; 513 bool suppressed = OnReport(rep, pc_or_addr != 0); 514 thr->is_freeing = old_is_freeing; 515 if (suppressed) 516 return false; 517 } 518 PrintReport(rep); 519 ctx->nreported++; 520 if (flags()->halt_on_error) 521 Die(); 522 return true; 523} 524 525bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace) { 526 ReadLock lock(&ctx->fired_suppressions_mtx); 527 for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) { 528 if (ctx->fired_suppressions[k].type != type) 529 continue; 530 for (uptr j = 0; j < trace.size; j++) { 531 FiredSuppression *s = &ctx->fired_suppressions[k]; 532 if (trace.trace[j] == s->pc_or_addr) { 533 if (s->supp) 534 atomic_fetch_add(&s->supp->hit_count, 1, memory_order_relaxed); 535 return true; 536 } 537 } 538 } 539 return false; 540} 541 542static bool IsFiredSuppression(Context *ctx, ReportType type, uptr addr) { 543 ReadLock lock(&ctx->fired_suppressions_mtx); 544 for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) { 545 if (ctx->fired_suppressions[k].type != type) 546 continue; 547 FiredSuppression *s = &ctx->fired_suppressions[k]; 548 if (addr == s->pc_or_addr) { 549 if (s->supp) 550 atomic_fetch_add(&s->supp->hit_count, 1, memory_order_relaxed); 551 return true; 552 } 553 } 554 return false; 555} 556 557static bool RaceBetweenAtomicAndFree(ThreadState *thr) { 558 Shadow s0(thr->racy_state[0]); 559 Shadow s1(thr->racy_state[1]); 560 CHECK(!(s0.IsAtomic() && s1.IsAtomic())); 561 if (!s0.IsAtomic() && !s1.IsAtomic()) 562 return true; 563 if (s0.IsAtomic() && s1.IsFreed()) 564 return true; 565 if (s1.IsAtomic() && thr->is_freeing) 566 return true; 567 return false; 568} 569 570void ReportRace(ThreadState *thr) { 571 CheckNoLocks(thr); 572 573 // Symbolizer makes lots of intercepted calls. If we try to process them, 574 // at best it will cause deadlocks on internal mutexes. 575 ScopedIgnoreInterceptors ignore; 576 577 if (!flags()->report_bugs) 578 return; 579 if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr)) 580 return; 581 582 bool freed = false; 583 { 584 Shadow s(thr->racy_state[1]); 585 freed = s.GetFreedAndReset(); 586 thr->racy_state[1] = s.raw(); 587 } 588 589 uptr addr = ShadowToMem((uptr)thr->racy_shadow_addr); 590 uptr addr_min = 0; 591 uptr addr_max = 0; 592 { 593 uptr a0 = addr + Shadow(thr->racy_state[0]).addr0(); 594 uptr a1 = addr + Shadow(thr->racy_state[1]).addr0(); 595 uptr e0 = a0 + Shadow(thr->racy_state[0]).size(); 596 uptr e1 = a1 + Shadow(thr->racy_state[1]).size(); 597 addr_min = min(a0, a1); 598 addr_max = max(e0, e1); 599 if (IsExpectedReport(addr_min, addr_max - addr_min)) 600 return; 601 } 602 603 ReportType typ = ReportTypeRace; 604 if (thr->is_vptr_access && freed) 605 typ = ReportTypeVptrUseAfterFree; 606 else if (thr->is_vptr_access) 607 typ = ReportTypeVptrRace; 608 else if (freed) 609 typ = ReportTypeUseAfterFree; 610 611 if (IsFiredSuppression(ctx, typ, addr)) 612 return; 613 614 const uptr kMop = 2; 615 VarSizeStackTrace traces[kMop]; 616 const uptr toppc = TraceTopPC(thr); 617 ObtainCurrentStack(thr, toppc, &traces[0]); 618 if (IsFiredSuppression(ctx, typ, traces[0])) 619 return; 620 621 // MutexSet is too large to live on stack. 622 Vector<u64> mset_buffer(MBlockScopedBuf); 623 mset_buffer.Resize(sizeof(MutexSet) / sizeof(u64) + 1); 624 MutexSet *mset2 = new(&mset_buffer[0]) MutexSet(); 625 626 Shadow s2(thr->racy_state[1]); 627 RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2); 628 if (IsFiredSuppression(ctx, typ, traces[1])) 629 return; 630 631 if (HandleRacyStacks(thr, traces, addr_min, addr_max)) 632 return; 633 634 ThreadRegistryLock l0(ctx->thread_registry); 635 ScopedReport rep(typ); 636 for (uptr i = 0; i < kMop; i++) { 637 Shadow s(thr->racy_state[i]); 638 rep.AddMemoryAccess(addr, s, traces[i], i == 0 ? &thr->mset : mset2); 639 } 640 641 for (uptr i = 0; i < kMop; i++) { 642 FastState s(thr->racy_state[i]); 643 ThreadContext *tctx = static_cast<ThreadContext*>( 644 ctx->thread_registry->GetThreadLocked(s.tid())); 645 if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1) 646 continue; 647 rep.AddThread(tctx); 648 } 649 650 rep.AddLocation(addr_min, addr_max - addr_min); 651 652#ifndef SANITIZER_GO 653 { // NOLINT 654 Shadow s(thr->racy_state[1]); 655 if (s.epoch() <= thr->last_sleep_clock.get(s.tid())) 656 rep.AddSleep(thr->last_sleep_stack_id); 657 } 658#endif 659 660 if (!OutputReport(thr, rep)) 661 return; 662 663 AddRacyStacks(thr, traces, addr_min, addr_max); 664} 665 666void PrintCurrentStack(ThreadState *thr, uptr pc) { 667 VarSizeStackTrace trace; 668 ObtainCurrentStack(thr, pc, &trace); 669 PrintStack(SymbolizeStack(trace)); 670} 671 672void PrintCurrentStackSlow(uptr pc) { 673#ifndef SANITIZER_GO 674 BufferedStackTrace *ptrace = 675 new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace))) 676 BufferedStackTrace(); 677 ptrace->Unwind(kStackTraceMax, pc, 0, 0, 0, 0, false); 678 for (uptr i = 0; i < ptrace->size / 2; i++) { 679 uptr tmp = ptrace->trace_buffer[i]; 680 ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1]; 681 ptrace->trace_buffer[ptrace->size - i - 1] = tmp; 682 } 683 PrintStack(SymbolizeStack(*ptrace)); 684#endif 685} 686 687} // namespace __tsan 688 689using namespace __tsan; 690 691extern "C" { 692SANITIZER_INTERFACE_ATTRIBUTE 693void __sanitizer_print_stack_trace() { 694 PrintCurrentStackSlow(StackTrace::GetCurrentPc()); 695} 696} // extern "C" 697