tsan_rtl_report.cc revision 5164ad434eccbfa9ad8097cf25146626313643f9
16fbecdd97512bd7d9ccef130e99650d446b50444Alexey Samsonov//===-- tsan_rtl_report.cc ------------------------------------------------===// 27ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 37ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// The LLVM Compiler Infrastructure 47ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 57ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is distributed under the University of Illinois Open Source 67ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// License. See LICENSE.TXT for details. 77ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 87ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===// 97ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is a part of ThreadSanitizer (TSan), a race detector. 117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===// 137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 14c0d78c1de1f2607c874020d27b72cf989c5ce092Alexey Samsonov#include "sanitizer_common/sanitizer_libc.h" 1547b1634df012507799eb39aa17d4022d748ba67bAlexey Samsonov#include "sanitizer_common/sanitizer_placement_new.h" 167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_platform.h" 177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h" 187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_suppressions.h" 197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_symbolize.h" 207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_report.h" 217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_sync.h" 227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_mman.h" 237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_flags.h" 247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 2515a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonovnamespace __sanitizer { 2615a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonovusing namespace __tsan; 2715a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov 2815a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonovvoid CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) { 2915a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov ScopedInRtl in_rtl; 305164ad434eccbfa9ad8097cf25146626313643f9Alexey Samsonov TsanPrintf("FATAL: ThreadSanitizer CHECK failed: " 315164ad434eccbfa9ad8097cf25146626313643f9Alexey Samsonov "%s:%d \"%s\" (0x%zx, 0x%zx)\n", 3215a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov file, line, cond, (uptr)v1, (uptr)v2); 3315a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov Die(); 3415a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov} 3515a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov 3615a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov} // namespace __sanitizer 3715a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov 387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan { 397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// Can be overriden by an application/test to intercept reports. 417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanybool WEAK OnReport(const ReportDesc *rep, bool suppressed) { 427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany (void)rep; 437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return suppressed; 447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void StackStripMain(ReportStack *stack) { 477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportStack *last_frame = 0; 487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportStack *last_frame2 = 0; 49f54c0e3321e2381fca3f02faefaaa6639d59c7cfDmitry Vyukov const char *prefix = "__interceptor_"; 507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr prefix_len = internal_strlen(prefix); 517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany const char *path_prefix = flags()->strip_path_prefix; 527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr path_prefix_len = internal_strlen(path_prefix); 537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (ReportStack *ent = stack; ent; ent = ent->next) { 54d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov if (ent->func && 0 == internal_strncmp(ent->func, prefix, prefix_len)) 557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ent->func += prefix_len; 56d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov if (ent->file && 0 == internal_strncmp(ent->file, path_prefix, 577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany path_prefix_len)) 587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ent->file += path_prefix_len; 597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (ent->file && ent->file[0] == '.' && ent->file[1] == '/') 607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ent->file += 2; 617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany last_frame2 = last_frame; 627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany last_frame = ent; 637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (last_frame2 == 0) 667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany const char *last = last_frame->func; 68cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov#ifndef TSAN_GO 697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany const char *last2 = last_frame2->func; 707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // Strip frame above 'main' 717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (last2 && 0 == internal_strcmp(last2, "main")) { 727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany last_frame2->next = 0; 737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // Strip our internal thread start routine. 747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) { 757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany last_frame2->next = 0; 767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // Strip global ctors init. 777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) { 787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany last_frame2->next = 0; 797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // If both are 0, then we probably just failed to symbolize. 807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } else if (last || last2) { 817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // Ensure that we recovered stack completely. Trimmed stack 827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // can actually happen if we do not instrument some code, 837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // so it's only a DCHECK. However we must try hard to not miss it 847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // due to our fault. 85e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov TsanPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc); 867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 87cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov#else 88cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov if (last && 0 == internal_strcmp(last, "schedunlock")) 89cb3a6b82ae406613f8870519d2acda1ee1c8f2b5Dmitry Vyukov last_frame2->next = 0; 90c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif 917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic ReportStack *SymbolizeStack(const StackTrace& trace) { 947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (trace.IsEmpty()) 957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return 0; 967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportStack *stack = 0; 977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (uptr si = 0; si < trace.Size(); si++) { 987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // We obtain the return address, that is, address of the next instruction, 997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // so offset it by 1 byte. 1007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany bool is_last = (si == trace.Size() - 1); 1017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportStack *ent = SymbolizeCode(trace.Get(si) - !is_last); 1027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_NE(ent, 0); 1037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportStack *last = ent; 1047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany while (last->next) { 1057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany last->pc += !is_last; 1067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany last = last->next; 1077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 1087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany last->pc += !is_last; 1097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany last->next = stack; 1107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany stack = ent; 1117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 1127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany StackStripMain(stack); 1137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return stack; 1147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1167ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyScopedReport::ScopedReport(ReportType typ) { 1177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ctx_ = CTX(); 1187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc)); 1197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep_ = new(mem) ReportDesc; 1207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep_->typ = typ; 1217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ctx_->report_mtx.Lock(); 1227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1247ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyScopedReport::~ScopedReport() { 1257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ctx_->report_mtx.Unlock(); 1267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep_->~ReportDesc(); 1277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany internal_free(rep_); 1287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddStack(const StackTrace *stack) { 1317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportStack **rs = rep_->stacks.PushBack(); 1327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany *rs = SymbolizeStack(*stack); 1337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddMemoryAccess(uptr addr, Shadow s, 1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany const StackTrace *stack) { 1377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop)); 1387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportMop *mop = new(mem) ReportMop; 1397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep_->mops.PushBack(mop); 1407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany mop->tid = s.tid(); 1417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany mop->addr = addr + s.addr0(); 1427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany mop->size = s.size(); 1437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany mop->write = s.is_write(); 1447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany mop->nmutex = 0; 1457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany mop->stack = SymbolizeStack(*stack); 1467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddThread(const ThreadContext *tctx) { 1497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread)); 1507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportThread *rt = new(mem) ReportThread(); 1517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep_->threads.PushBack(rt); 1527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rt->id = tctx->tid; 1537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rt->running = (tctx->status == ThreadStatusRunning); 1547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rt->stack = SymbolizeStack(tctx->creation_stack); 1557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddMutex(const SyncVar *s) { 1587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex)); 1597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportMutex *rm = new(mem) ReportMutex(); 1607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep_->mutexes.PushBack(rm); 1617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rm->id = 42; 1627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rm->stack = SymbolizeStack(s->creation_stack); 1637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ScopedReport::AddLocation(uptr addr, uptr size) { 1667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportStack *symb = SymbolizeData(addr); 1677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (symb) { 1687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation)); 1697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ReportLocation *loc = new(mem) ReportLocation(); 1707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep_->locs.PushBack(loc); 1717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany loc->type = ReportLocationGlobal; 1727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany loc->addr = addr; 1737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany loc->size = size; 1747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany loc->tid = 0; 1757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany loc->name = symb->func; 1767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany loc->file = symb->file; 1777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany loc->line = symb->line; 1787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany loc->stack = 0; 1797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany internal_free(symb); 1807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 1817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyconst ReportDesc *ScopedReport::GetReport() const { 1847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return rep_; 1857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void RestoreStack(int tid, const u64 epoch, StackTrace *stk) { 1887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ThreadContext *tctx = CTX()->threads[tid]; 1897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (tctx == 0) 1907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 1917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Trace* trace = 0; 1927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (tctx->status == ThreadStatusRunning) { 1937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK(tctx->thr); 1947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany trace = &tctx->thr->trace; 1957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } else if (tctx->status == ThreadStatusFinished 1967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany || tctx->status == ThreadStatusDead) { 1979d2ffc2ee08216f8fad9b1bd267d1f112e0d2f01Dmitry Vyukov if (tctx->dead_info == 0) 1989d2ffc2ee08216f8fad9b1bd267d1f112e0d2f01Dmitry Vyukov return; 1999d2ffc2ee08216f8fad9b1bd267d1f112e0d2f01Dmitry Vyukov trace = &tctx->dead_info->trace; 2007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } else { 2017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 2027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Lock l(&trace->mtx); 2047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany const int partidx = (epoch / (kTraceSize / kTraceParts)) % kTraceParts; 2057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany TraceHeader* hdr = &trace->headers[partidx]; 2067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (epoch < hdr->epoch0) 2077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 2087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany const u64 eend = epoch % kTraceSize; 2097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany const u64 ebegin = eend / kTracePartSize * kTracePartSize; 210e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n", 211e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx); 2127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany InternalScopedBuf<uptr> stack(1024); // FIXME: de-hardcode 1024 2137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (uptr i = 0; i < hdr->stack0.Size(); i++) { 2147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany stack[i] = hdr->stack0.Get(i); 215e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov DPrintf2(" #%02lu: pc=%zx\n", i, stack[i]); 2167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr pos = hdr->stack0.Size(); 2187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (uptr i = ebegin; i <= eend; i++) { 2197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Event ev = trace->events[i]; 2207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany EventType typ = (EventType)(ev >> 61); 2217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr pc = (uptr)(ev & 0xffffffffffffull); 222e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov DPrintf2(" %zu typ=%d pc=%zx\n", i, typ, pc); 2237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (typ == EventTypeMop) { 2247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany stack[pos] = pc; 2257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } else if (typ == EventTypeFuncEnter) { 2267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany stack[pos++] = pc; 2277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } else if (typ == EventTypeFuncExit) { 2287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // Since we have full stacks, this should never happen. 2297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany DCHECK_GT(pos, 0); 2307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (pos > 0) 2317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany pos--; 2327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (uptr j = 0; j <= pos; j++) 234e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov DPrintf2(" #%zu: %zx\n", j, stack[j]); 2357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (pos == 0 && stack[0] == 0) 2377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 2387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany pos++; 2397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany stk->Init(stack, pos); 2407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 2417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 2427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic bool HandleRacyStacks(ThreadState *thr, const StackTrace (&traces)[2], 2437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr addr_min, uptr addr_max) { 2447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Context *ctx = CTX(); 2457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany bool equal_stack = false; 2467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany RacyStacks hash = {}; 2477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (flags()->suppress_equal_stacks) { 2487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr)); 2497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr)); 2507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) { 2517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (hash == ctx->racy_stacks[i]) { 2527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n"); 2537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany equal_stack = true; 2547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany break; 2557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany bool equal_address = false; 2597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany RacyAddress ra0 = {addr_min, addr_max}; 2607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (flags()->suppress_equal_addresses) { 2617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) { 2627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany RacyAddress ra2 = ctx->racy_addresses[i]; 2637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr maxbeg = max(ra0.addr_min, ra2.addr_min); 2647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr minend = min(ra0.addr_max, ra2.addr_max); 2657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (maxbeg < minend) { 2667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany DPrintf("ThreadSanitizer: suppressing report as doubled (addr)\n"); 2677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany equal_address = true; 2687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany break; 2697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (equal_stack || equal_address) { 2737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (!equal_stack) 2747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ctx->racy_stacks.PushBack(hash); 2757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (!equal_address) 2767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ctx->racy_addresses.PushBack(ra0); 2777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return true; 2787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return false; 2807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 2817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 2827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2], 2837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr addr_min, uptr addr_max) { 2847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Context *ctx = CTX(); 2857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (flags()->suppress_equal_stacks) { 2867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany RacyStacks hash; 2877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr)); 2887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr)); 2897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ctx->racy_stacks.PushBack(hash); 2907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (flags()->suppress_equal_addresses) { 2927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany RacyAddress ra0 = {addr_min, addr_max}; 2937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ctx->racy_addresses.PushBack(ra0); 2947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 2967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 297f5820e74ad31eb8352049c880f8d58e286a9b713Dmitry Vyukovbool OutputReport(const ScopedReport &srep, const ReportStack *suppress_stack) { 2987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany const ReportDesc *rep = srep.GetReport(); 2997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany bool suppressed = IsSuppressed(rep->typ, suppress_stack); 3007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany suppressed = OnReport(rep, suppressed); 3017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (suppressed) 3027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return false; 3037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany PrintReport(rep); 3047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CTX()->nreported++; 3057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return true; 3067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 3077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid ReportRace(ThreadState *thr) { 3097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ScopedInRtl in_rtl; 310069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov 311069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov bool freed = false; 312069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov { 313069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov Shadow s(thr->racy_state[1]); 314069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov freed = s.GetFreedAndReset(); 315069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov thr->racy_state[1] = s.raw(); 316069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov } 317069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov 3187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr addr = ShadowToMem((uptr)thr->racy_shadow_addr); 3197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr addr_min = 0; 3207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr addr_max = 0; 3217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany { 3227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr a0 = addr + Shadow(thr->racy_state[0]).addr0(); 3237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr a1 = addr + Shadow(thr->racy_state[1]).addr0(); 3247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr e0 = a0 + Shadow(thr->racy_state[0]).size(); 3257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany uptr e1 = a1 + Shadow(thr->racy_state[1]).size(); 3267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany addr_min = min(a0, a1); 3277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany addr_max = max(e0, e1); 3287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (IsExpectedReport(addr_min, addr_max - addr_min)) 3297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 3307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 3317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Context *ctx = CTX(); 3337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Lock l0(&ctx->thread_mtx); 3347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 335069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov ScopedReport rep(freed ? ReportTypeUseAfterFree : ReportTypeRace); 336069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov const uptr kMop = 2; 337069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov StackTrace traces[kMop]; 338069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov for (uptr i = 0; i < kMop; i++) { 3397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Shadow s(thr->racy_state[i]); 3407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany RestoreStack(s.tid(), s.epoch(), &traces[i]); 3417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 3427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (HandleRacyStacks(thr, traces, addr_min, addr_max)) 3447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 3457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 346069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov for (uptr i = 0; i < kMop; i++) { 3477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Shadow s(thr->racy_state[i]); 3487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep.AddMemoryAccess(addr, s, &traces[i]); 3497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 3507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // Ensure that we have at least something for the current thread. 3527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_EQ(traces[0].IsEmpty(), false); 3537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 354069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov for (uptr i = 0; i < kMop; i++) { 3557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany FastState s(thr->racy_state[i]); 3567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ThreadContext *tctx = ctx->threads[s.tid()]; 3577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1) 3587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany continue; 3597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep.AddThread(tctx); 3607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 3617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (!OutputReport(rep, rep.GetReport()->mops[0]->stack)) 3637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 3647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany AddRacyStacks(thr, traces, addr_min, addr_max); 3667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 3677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} // namespace __tsan 369