tsan_rtl.cc revision 9578a3ecfc35a264ede1135033398e2a77a6cad6
1603c4be006d8c53905d736bf1f19a49f5ce98276Alexey Samsonov//===-- tsan_rtl.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// Main file (entry points) for the TSan run-time.
137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
15fce5bd4cc29fddb5e8f0cb9c12df7c10187a991dDmitry Vyukov#include "sanitizer_common/sanitizer_atomic.h"
160969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov#include "sanitizer_common/sanitizer_common.h"
1716e0075746b21ed866ec3be21ef0d1e46f0efed5Kostya Serebryany#include "sanitizer_common/sanitizer_libc.h"
18848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov#include "sanitizer_common/sanitizer_stackdepot.h"
1947b1634df012507799eb39aa17d4022d748ba67bAlexey Samsonov#include "sanitizer_common/sanitizer_placement_new.h"
208cc1f81b2cc1fa0d4cda4f4635d955aed04c09c8Alexey Samsonov#include "sanitizer_common/sanitizer_symbolizer.h"
217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_defs.h"
227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_platform.h"
237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h"
247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_mman.h"
257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_suppressions.h"
26a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov#include "tsan_symbolize.h"
277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
28adfb65039646774f0f063b538f8fb0aec021f42bDmitry Vyukovvolatile int __tsan_resumed = 0;
297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyextern "C" void __tsan_resume() {
31adfb65039646774f0f063b538f8fb0aec021f42bDmitry Vyukov  __tsan_resumed = 1;
327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan {
357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
36b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#ifndef TSAN_GO
370a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey SamsonovTHREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
38b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#endif
390a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonovstatic char ctx_placeholder[sizeof(Context)] ALIGNED(64);
407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4122881ec8c8a3c01f9b993b186040444b0b5caa50Dmitry Vyukov// Can be overriden by a front-end.
427c984ca2fc88e2cd82b30c5b3ef361af2a1f2062Dmitry Vyukovbool CPP_WEAK OnFinalize(bool failed) {
4322881ec8c8a3c01f9b993b186040444b0b5caa50Dmitry Vyukov  return failed;
4422881ec8c8a3c01f9b993b186040444b0b5caa50Dmitry Vyukov}
4522881ec8c8a3c01f9b993b186040444b0b5caa50Dmitry Vyukov
467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic Context *ctx;
477ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyContext *CTX() {
487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return ctx;
497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
512bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonovstatic char thread_registry_placeholder[sizeof(ThreadRegistry)];
522bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov
532bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonovstatic ThreadContextBase *CreateThreadContext(u32 tid) {
542bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  // Map thread trace when context is created.
552bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event));
569743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  MapThreadTrace(GetThreadTraceHeader(tid), sizeof(Trace));
579743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  new(ThreadTrace(tid)) Trace();
589743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
592bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  return new(mem) ThreadContext(tid);
602bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov}
612bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov
622bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov#ifndef TSAN_GO
632bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonovstatic const u32 kThreadQuarantineSize = 16;
642bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov#else
652bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonovstatic const u32 kThreadQuarantineSize = 64;
662bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov#endif
672bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov
687ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyContext::Context()
697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  : initialized()
707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , report_mtx(MutexTypeReport, StatMtxReport)
717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , nreported()
727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , nmissed_expected()
732bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  , thread_registry(new(thread_registry_placeholder) ThreadRegistry(
742bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov      CreateThreadContext, kMaxTid, kThreadQuarantineSize))
757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , racy_stacks(MBlockRacyStacks)
76158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  , racy_addresses(MBlockRacyAddresses)
77158c6ac3bb46753db217f9c2c73485811a3a1890Dmitry Vyukov  , fired_suppressions(MBlockRacyAddresses) {
787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// The objects are allocated in TLS, so one may rely on zero-initialization.
81ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry VyukovThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany                         uptr stk_addr, uptr stk_size,
837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany                         uptr tls_addr, uptr tls_size)
847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  : fast_state(tid, epoch)
857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Do not touch these, rely on zero initialization,
867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // they may be accessed before the ctor.
877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // , fast_ignore_reads()
887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // , fast_ignore_writes()
897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // , in_rtl()
907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , shadow_stack_pos(&shadow_stack[0])
918b30c254a63a7421dd81d13dee086a54c4ca134bDmitry Vyukov#ifndef TSAN_GO
928b30c254a63a7421dd81d13dee086a54c4ca134bDmitry Vyukov  , jmp_bufs(MBlockJmpBuf)
938b30c254a63a7421dd81d13dee086a54c4ca134bDmitry Vyukov#endif
947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , tid(tid)
95ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov  , unique_id(unique_id)
967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , stk_addr(stk_addr)
977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , stk_size(stk_size)
987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , tls_addr(tls_addr)
997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , tls_size(tls_size) {
1007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
102a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukovstatic void MemoryProfiler(Context *ctx, fd_t fd, int i) {
1034bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  uptr n_threads;
1044bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  uptr n_running_threads;
1054bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads);
106a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov  InternalScopedBuffer<char> buf(4096);
1074bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  internal_snprintf(buf.data(), buf.size(), "%d: nthr=%d nlive=%d\n",
1084bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov      i, n_threads, n_running_threads);
1094bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  internal_write(fd, buf.data(), internal_strlen(buf.data()));
1104bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  WriteMemoryProfile(buf.data(), buf.size());
1114bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  internal_write(fd, buf.data(), internal_strlen(buf.data()));
1124bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov}
1134bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov
1144bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukovstatic void BackgroundThread(void *arg) {
1154bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  ScopedInRtl in_rtl;
116a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov  Context *ctx = CTX();
117f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov  const u64 kMs2Ns = 1000 * 1000;
1184bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov
1194bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  fd_t mprof_fd = kInvalidFd;
1204bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  if (flags()->profile_memory && flags()->profile_memory[0]) {
1214bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov    InternalScopedBuffer<char> filename(4096);
1224bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov    internal_snprintf(filename.data(), filename.size(), "%s.%d",
1234bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov        flags()->profile_memory, GetPid());
1249578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne    uptr openrv = OpenFile(filename.data(), true);
1259578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne    if (internal_iserror(openrv)) {
1264bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov      Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
1274bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov          &filename[0]);
1289578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne    } else {
1299578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne      mprof_fd = openrv;
1304bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov    }
1314bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  }
1324bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov
1334bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  u64 last_flush = NanoTime();
13426127735454fddae3495794f38189d57dde6510fDmitry Vyukov  for (int i = 0; ; i++) {
1350969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov    SleepForSeconds(1);
1364bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov    u64 now = NanoTime();
13726127735454fddae3495794f38189d57dde6510fDmitry Vyukov
138a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov    // Flush memory if requested.
1394bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov    if (flags()->flush_memory_ms) {
140f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov      if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) {
1414bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov        FlushShadowMemory();
1424bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov        last_flush = NanoTime();
1434bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov      }
1444bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov    }
1454bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov
146a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov    // Write memory profile if requested.
1474bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov    if (mprof_fd != kInvalidFd)
148a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov      MemoryProfiler(ctx, mprof_fd, i);
149a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov
150a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov#ifndef TSAN_GO
151f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov    // Flush symbolizer cache if requested.
152f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov    if (flags()->flush_symbolizer_ms > 0) {
153f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov      u64 last = atomic_load(&ctx->last_symbolize_time_ns,
154f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov                             memory_order_relaxed);
155f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov      if (last != 0 && last + flags()->flush_symbolizer_ms * kMs2Ns < now) {
156f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov        Lock l(&ctx->report_mtx);
1577ed46ff7af911da0dd2067734d1408c6986c6657Alexey Samsonov        SpinMutexLock l2(&CommonSanitizerReportMutex);
158f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov        SymbolizeFlush();
159f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov        atomic_store(&ctx->last_symbolize_time_ns, 0, memory_order_relaxed);
160f63dde3594da0dba4c8039f0cb3a4196a76f1affDmitry Vyukov      }
161a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov    }
162a38e40fde45acccb124f7419ecbe21ef6cfd306bDmitry Vyukov#endif
16326127735454fddae3495794f38189d57dde6510fDmitry Vyukov  }
16426127735454fddae3495794f38189d57dde6510fDmitry Vyukov}
16526127735454fddae3495794f38189d57dde6510fDmitry Vyukov
1667ac33ac529ff93a57419f5ddf71b1fde68428577Dmitry Vyukovvoid DontNeedShadowFor(uptr addr, uptr size) {
1677ac33ac529ff93a57419f5ddf71b1fde68428577Dmitry Vyukov  uptr shadow_beg = MemToShadow(addr);
1687ac33ac529ff93a57419f5ddf71b1fde68428577Dmitry Vyukov  uptr shadow_end = MemToShadow(addr + size);
1697ac33ac529ff93a57419f5ddf71b1fde68428577Dmitry Vyukov  FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
1707ac33ac529ff93a57419f5ddf71b1fde68428577Dmitry Vyukov}
1717ac33ac529ff93a57419f5ddf71b1fde68428577Dmitry Vyukov
172a05fcc1e3e045097f2f1a20798cbe038bbb1d6a9Dmitry Vyukovvoid MapShadow(uptr addr, uptr size) {
1736b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov  MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier);
174a05fcc1e3e045097f2f1a20798cbe038bbb1d6a9Dmitry Vyukov}
175a05fcc1e3e045097f2f1a20798cbe038bbb1d6a9Dmitry Vyukov
1766535c31c66569df262791f0b56852c496977c977Dmitry Vyukovvoid MapThreadTrace(uptr addr, uptr size) {
177dae1251f196f9694d428a04f14987b06112ae52cDmitry Vyukov  DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
1786535c31c66569df262791f0b56852c496977c977Dmitry Vyukov  CHECK_GE(addr, kTraceMemBegin);
1796535c31c66569df262791f0b56852c496977c977Dmitry Vyukov  CHECK_LE(addr + size, kTraceMemBegin + kTraceMemSize);
1806535c31c66569df262791f0b56852c496977c977Dmitry Vyukov  if (addr != (uptr)MmapFixedNoReserve(addr, size)) {
1816535c31c66569df262791f0b56852c496977c977Dmitry Vyukov    Printf("FATAL: ThreadSanitizer can not mmap thread trace\n");
1826535c31c66569df262791f0b56852c496977c977Dmitry Vyukov    Die();
1836535c31c66569df262791f0b56852c496977c977Dmitry Vyukov  }
1846535c31c66569df262791f0b56852c496977c977Dmitry Vyukov}
1856535c31c66569df262791f0b56852c496977c977Dmitry Vyukov
1867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid Initialize(ThreadState *thr) {
1877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Thread safe because done before all threads exist.
1887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  static bool is_initialized = false;
1897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (is_initialized)
1907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
1917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  is_initialized = true;
192859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany  SanitizerToolName = "ThreadSanitizer";
193591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov  // Install tool-specific callbacks in sanitizer_common.
194591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov  SetCheckFailedCallback(TsanCheckFailed);
195591616d323d73b7ea7cd8fea4eec46cedccda27eAlexey Samsonov
1967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ScopedInRtl in_rtl;
197bbbb20b7212155ebc5b5b4ee1c68c987dcf30320Dmitry Vyukov#ifndef TSAN_GO
1982e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov  InitializeAllocator();
199bbbb20b7212155ebc5b5b4ee1c68c987dcf30320Dmitry Vyukov#endif
2007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  InitializeInterceptors();
2017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  const char *env = InitializePlatform();
2027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  InitializeMutex();
2037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  InitializeDynamicAnnotations();
2047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ctx = new(ctx_placeholder) Context;
205a05fcc1e3e045097f2f1a20798cbe038bbb1d6a9Dmitry Vyukov#ifndef TSAN_GO
2067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  InitializeShadowMemory();
207a05fcc1e3e045097f2f1a20798cbe038bbb1d6a9Dmitry Vyukov#endif
2087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  InitializeFlags(&ctx->flags, env);
209b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  // Setup correct file descriptor for error reports.
210cec6068bbbbfb84285c0856c196c48170924e215Dmitry Vyukov  if (internal_strcmp(flags()->log_path, "stdout") == 0)
211cec6068bbbbfb84285c0856c196c48170924e215Dmitry Vyukov    __sanitizer_set_report_fd(kStdoutFd);
212cec6068bbbbfb84285c0856c196c48170924e215Dmitry Vyukov  else if (internal_strcmp(flags()->log_path, "stderr") == 0)
213cec6068bbbbfb84285c0856c196c48170924e215Dmitry Vyukov    __sanitizer_set_report_fd(kStderrFd);
214cec6068bbbbfb84285c0856c196c48170924e215Dmitry Vyukov  else
215cec6068bbbbfb84285c0856c196c48170924e215Dmitry Vyukov    __sanitizer_set_report_path(flags()->log_path);
2167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  InitializeSuppressions();
21785a6dad26739fcd9742eae04b4a539e29889e937Dmitry Vyukov#ifndef TSAN_GO
21868bdcc4db8802c9a6f72d0e684a336ab92a3785bAlexey Samsonov  // Initialize external symbolizer before internal threads are started.
2198cc1f81b2cc1fa0d4cda4f4635d955aed04c09c8Alexey Samsonov  const char *external_symbolizer = flags()->external_symbolizer_path;
2208cc1f81b2cc1fa0d4cda4f4635d955aed04c09c8Alexey Samsonov  if (external_symbolizer != 0 && external_symbolizer[0] != '\0') {
22193b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov    if (!InitializeExternalSymbolizer(external_symbolizer)) {
22293b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov      Printf("Failed to start external symbolizer: '%s'\n",
22393b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov             external_symbolizer);
22493b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov      Die();
22593b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov    }
2268cc1f81b2cc1fa0d4cda4f4635d955aed04c09c8Alexey Samsonov  }
22785a6dad26739fcd9742eae04b4a539e29889e937Dmitry Vyukov#endif
2284bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  internal_start_thread(&BackgroundThread, 0);
2298cc1f81b2cc1fa0d4cda4f4635d955aed04c09c8Alexey Samsonov
2307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (ctx->flags.verbosity)
231b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("***** Running under ThreadSanitizer v2 (pid %d) *****\n",
23267a64dd8259fdbd867633b27f54d584f435f1ce6Alexey Samsonov               GetPid());
2337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Initialize thread 0.
2357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  int tid = ThreadCreate(thr, 0, 0, true);
2367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  CHECK_EQ(tid, 0);
2377dccf3f92a867f917ad19f9a6b37bcf93e64b35bDmitry Vyukov  ThreadStart(thr, tid, GetPid());
2387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  CHECK_EQ(thr->in_rtl, 1);
2397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ctx->initialized = true;
2407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
241adfb65039646774f0f063b538f8fb0aec021f42bDmitry Vyukov  if (flags()->stop_on_start) {
242b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("ThreadSanitizer is suspended at startup (pid %d)."
243adfb65039646774f0f063b538f8fb0aec021f42bDmitry Vyukov           " Call __tsan_resume().\n",
244adfb65039646774f0f063b538f8fb0aec021f42bDmitry Vyukov           GetPid());
245ba5e99668e3030cc5bab357a04271a1bdbac209cAlexey Samsonov    while (__tsan_resumed == 0) {}
2467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
2477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyint Finalize(ThreadState *thr) {
2507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ScopedInRtl in_rtl;
2517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Context *ctx = __tsan::ctx;
2527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  bool failed = false;
2537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
25454e0a9a391616bbd2a4f0fd2d01076291274cb98Dmitry Vyukov  if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1)
25554e0a9a391616bbd2a4f0fd2d01076291274cb98Dmitry Vyukov    SleepForMillis(flags()->atexit_sleep_ms);
25654e0a9a391616bbd2a4f0fd2d01076291274cb98Dmitry Vyukov
257d0a51c02157e8293ea365ad0d429ef8e73d115deDmitry Vyukov  // Wait for pending reports.
258d0a51c02157e8293ea365ad0d429ef8e73d115deDmitry Vyukov  ctx->report_mtx.Lock();
2597ed46ff7af911da0dd2067734d1408c6986c6657Alexey Samsonov  CommonSanitizerReportMutex.Lock();
2607ed46ff7af911da0dd2067734d1408c6986c6657Alexey Samsonov  CommonSanitizerReportMutex.Unlock();
261d0a51c02157e8293ea365ad0d429ef8e73d115deDmitry Vyukov  ctx->report_mtx.Unlock();
262d0a51c02157e8293ea365ad0d429ef8e73d115deDmitry Vyukov
263bdd844cb41718c27ef727a99a236191bc29a3df8Dmitry Vyukov#ifndef TSAN_GO
264bdd844cb41718c27ef727a99a236191bc29a3df8Dmitry Vyukov  if (ctx->flags.verbosity)
265bdd844cb41718c27ef727a99a236191bc29a3df8Dmitry Vyukov    AllocatorPrintStats();
266bdd844cb41718c27ef727a99a236191bc29a3df8Dmitry Vyukov#endif
267bdd844cb41718c27ef727a99a236191bc29a3df8Dmitry Vyukov
2687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ThreadFinalize(thr);
2697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (ctx->nreported) {
2717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    failed = true;
272b3b21231dd9dfeb34f5f302c879f2d11b6312080Dmitry Vyukov#ifndef TSAN_GO
273b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("ThreadSanitizer: reported %d warnings\n", ctx->nreported);
274b3b21231dd9dfeb34f5f302c879f2d11b6312080Dmitry Vyukov#else
275b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("Found %d data race(s)\n", ctx->nreported);
276b3b21231dd9dfeb34f5f302c879f2d11b6312080Dmitry Vyukov#endif
2777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
2787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (ctx->nmissed_expected) {
2807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    failed = true;
281b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("ThreadSanitizer: missed %d expected races\n",
2827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        ctx->nmissed_expected);
2837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
2847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
285f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov  if (flags()->print_suppressions)
286f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov    PrintMatchedSuppressions();
2870fd908cf5a555483633e2d9703932bde18009682Dmitry Vyukov#ifndef TSAN_GO
2880fd908cf5a555483633e2d9703932bde18009682Dmitry Vyukov  if (flags()->print_benign)
2890fd908cf5a555483633e2d9703932bde18009682Dmitry Vyukov    PrintMatchedBenignRaces();
2900fd908cf5a555483633e2d9703932bde18009682Dmitry Vyukov#endif
291f754eb501d6bd163fff6747716b7703fe45be4b8Dmitry Vyukov
29222881ec8c8a3c01f9b993b186040444b0b5caa50Dmitry Vyukov  failed = OnFinalize(failed);
29322881ec8c8a3c01f9b993b186040444b0b5caa50Dmitry Vyukov
29408adb1815b4958df88f904b9780a055b0d387294Dmitry Vyukov  StatAggregate(ctx->stat, thr->stat);
2957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StatOutput(ctx->stat);
296b7b6b1cd9df0c954b1f890fcebf373db984923b3Dmitry Vyukov  return failed ? flags()->exitcode : 0;
2977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2990ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#ifndef TSAN_GO
300848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovu32 CurrentStackId(ThreadState *thr, uptr pc) {
301848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  if (thr->shadow_stack_pos == 0)  // May happen during bootstrap.
302848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    return 0;
303848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  if (pc) {
304848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    thr->shadow_stack_pos[0] = pc;
305848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    thr->shadow_stack_pos++;
306848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  }
307848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  u32 id = StackDepotPut(thr->shadow_stack,
308848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov                         thr->shadow_stack_pos - thr->shadow_stack);
309848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  if (pc)
310848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    thr->shadow_stack_pos--;
311848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  return id;
312848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov}
3130ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov#endif
314848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
315b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukovvoid TraceSwitch(ThreadState *thr) {
3169ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  thr->nomalloc++;
3177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ScopedInRtl in_rtl;
3189743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  Trace *thr_trace = ThreadTrace(thr->tid);
3199743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  Lock l(&thr_trace->mtx);
3200415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov  unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts();
3219743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  TraceHeader *hdr = &thr_trace->headers[trace];
3227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  hdr->epoch0 = thr->fast_state.epoch();
3237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  hdr->stack0.ObtainCurrent(thr, 0);
324ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  hdr->mset0 = thr->mset;
3259ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  thr->nomalloc--;
3267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3289743d74426ae43898e4da55e591b09be18f8aa6eDmitry VyukovTrace *ThreadTrace(int tid) {
3299743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov  return (Trace*)GetThreadTraceHeader(tid);
3309743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov}
3319743d74426ae43898e4da55e591b09be18f8aa6eDmitry Vyukov
332385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukovuptr TraceTopPC(ThreadState *thr) {
333385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  Event *events = (Event*)GetThreadTrace(thr->tid);
334d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov  uptr pc = events[thr->fast_state.GetTracePos()];
335385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  return pc;
336385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov}
337385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov
338d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukovuptr TraceSize() {
339d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov  return (uptr)(1ull << (kTracePartSizeBits + flags()->history_size + 1));
340d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov}
341d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov
3420415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukovuptr TraceParts() {
3430415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov  return TraceSize() / kTracePartSize;
3440415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov}
3450415ac00935795a70d87ae662ccad58ea0704537Dmitry Vyukov
346b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#ifndef TSAN_GO
3477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyextern "C" void __tsan_trace_switch() {
3487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  TraceSwitch(cur_thread());
3497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyextern "C" void __tsan_report_race() {
3527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  ReportRace(cur_thread());
3537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
354b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#endif
3557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3567ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyALWAYS_INLINE
35743c36e4b055f348d6076e6da44f9cd3e4399568fTimur IskhodzhanovShadow LoadShadow(u64 *p) {
3587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  u64 raw = atomic_load((atomic_uint64_t*)p, memory_order_relaxed);
3597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return Shadow(raw);
3607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3627ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyALWAYS_INLINE
36343c36e4b055f348d6076e6da44f9cd3e4399568fTimur Iskhodzhanovvoid StoreShadow(u64 *sp, u64 s) {
3647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  atomic_store((atomic_uint64_t*)sp, s, memory_order_relaxed);
3657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3677ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyALWAYS_INLINE
36843c36e4b055f348d6076e6da44f9cd3e4399568fTimur Iskhodzhanovvoid StoreIfNotYetStored(u64 *sp, u64 *s) {
3697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StoreShadow(sp, *s);
3707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  *s = 0;
3717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic inline void HandleRace(ThreadState *thr, u64 *shadow_mem,
3747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany                              Shadow cur, Shadow old) {
3757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->racy_state[0] = cur.raw();
3767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->racy_state[1] = old.raw();
3777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->racy_shadow_addr = shadow_mem;
378b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#ifndef TSAN_GO
3797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  HACKY_CALL(__tsan_report_race);
380b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#else
381b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov  ReportRace(thr);
382b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#endif
3837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic inline bool OldIsInSameSynchEpoch(Shadow old, ThreadState *thr) {
3867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return old.epoch() >= thr->fast_synch_epoch;
3877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic inline bool HappensBefore(Shadow old, ThreadState *thr) {
390c8f0a00ede42f83ac79ff63c347ca8ddcda77155Dmitry Vyukov  return thr->clock.get(old.TidWithIgnore()) >= old.epoch();
3917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
393d475aa8578f4a1955cdb3e3159eda8b229f8c021Kostya SerebryanyALWAYS_INLINE USED
3947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid MemoryAccessImpl(ThreadState *thr, uptr addr,
395334553ec45d8982df45a6f5e656e068142ecde3fDmitry Vyukov    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
3967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    u64 *shadow_mem, Shadow cur) {
3977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StatInc(thr, StatMop);
3987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
3997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
4007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // This potentially can live in an MMX/SSE scratch register.
4027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // The required intrinsics are:
4037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // __m128i _mm_move_epi64(__m128i*);
4047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // _mm_storel_epi64(u64*, __m128i);
4057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  u64 store_word = cur.raw();
4067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // scan all the shadow values and dispatch to 4 categories:
4087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // same, replace, candidate and race (see comments below).
4097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // we consider only 3 cases regarding access sizes:
4107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // equal, intersect and not intersect. initially I considered
4117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // larger and smaller as well, it allowed to replace some
4127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // 'candidates' with 'same' or 'replace', but I think
4137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // it's just not worth it (performance- and complexity-wise).
4147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
415286c914d37d28df611ae083cac40148cf2622ee7Dmitry Vyukov  Shadow old(0);
4167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (kShadowCnt == 1) {
4177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    int idx = 0;
4187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (kShadowCnt == 2) {
4207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    int idx = 0;
4217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 1;
4237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (kShadowCnt == 4) {
4257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    int idx = 0;
4267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 1;
4287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 2;
4307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 3;
4327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (kShadowCnt == 8) {
4347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    int idx = 0;
4357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 1;
4377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 2;
4397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 3;
4417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 4;
4437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 5;
4457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 6;
4477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    idx = 7;
4497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_update_shadow_word_inl.h"
4507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else {
4517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    CHECK(false);
4527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
4537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // we did not find any races and had already stored
4557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // the current access info, so we are done
4567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (LIKELY(store_word == 0))
4577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
4587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // choose a random candidate slot and replace it
4597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StoreShadow(shadow_mem + (cur.epoch() % kShadowCnt), store_word);
4607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StatInc(thr, StatShadowReplace);
4617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return;
4627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany RACE:
4637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  HandleRace(thr, shadow_mem, cur, old);
4647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return;
4657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
4667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
4678ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukovvoid UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
4688ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    int size, bool kAccessIsWrite, bool kIsAtomic) {
4698ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov  while (size) {
4708ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    int size1 = 1;
4718ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    int kAccessSizeLog = kSizeLog1;
4728ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    if (size >= 8 && (addr & ~7) == ((addr + 8) & ~7)) {
4738ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov      size1 = 8;
4748ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov      kAccessSizeLog = kSizeLog8;
4758ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    } else if (size >= 4 && (addr & ~7) == ((addr + 4) & ~7)) {
4768ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov      size1 = 4;
4778ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov      kAccessSizeLog = kSizeLog4;
4788ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    } else if (size >= 2 && (addr & ~7) == ((addr + 2) & ~7)) {
4798ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov      size1 = 2;
4808ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov      kAccessSizeLog = kSizeLog2;
4818ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    }
4828ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    MemoryAccess(thr, pc, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic);
4838ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    addr += size1;
4848ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov    size -= size1;
4858ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov  }
4868ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov}
4878ecd0e5d9f389d18653892851c6ffb2f235de4b7Dmitry Vyukov
488d475aa8578f4a1955cdb3e3159eda8b229f8c021Kostya SerebryanyALWAYS_INLINE USED
4897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
490334553ec45d8982df45a6f5e656e068142ecde3fDmitry Vyukov    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {
4917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  u64 *shadow_mem = (u64*)MemToShadow(addr);
49268230a12bbd22c9402dd8f9af027fcb2e119f978Dmitry Vyukov  DPrintf2("#%d: MemoryAccess: @%p %p size=%d"
493e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov      " is_write=%d shadow_mem=%p {%zx, %zx, %zx, %zx}\n",
4947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      (int)thr->fast_state.tid(), (void*)pc, (void*)addr,
4957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      (int)(1 << kAccessSizeLog), kAccessIsWrite, shadow_mem,
496e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov      (uptr)shadow_mem[0], (uptr)shadow_mem[1],
497e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov      (uptr)shadow_mem[2], (uptr)shadow_mem[3]);
4987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#if TSAN_DEBUG
4997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (!IsAppMem(addr)) {
500b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("Access to non app mem %zx\n", addr);
5017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    DCHECK(IsAppMem(addr));
5027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
5037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (!IsShadowMem((uptr)shadow_mem)) {
504b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
5057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    DCHECK(IsShadowMem((uptr)shadow_mem));
5067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
5077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#endif
5087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
50982dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov  if (*shadow_mem == kShadowRodata) {
51082dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov    // Access to .rodata section, no races here.
51182dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov    // Measurements show that it can be 10-20% of all memory accesses.
51282dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov    StatInc(thr, StatMop);
51382dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov    StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
51482dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov    StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
51582dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov    StatInc(thr, StatMopRodata);
51682dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov    return;
51782dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov  }
51882dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov
5197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  FastState fast_state = thr->fast_state;
5207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (fast_state.GetIgnoreBit())
5217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
5227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  fast_state.IncrementEpoch();
5237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->fast_state = fast_state;
5247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Shadow cur(fast_state);
5257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  cur.SetAddr0AndSizeLog(addr & 7, kAccessSizeLog);
5267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  cur.SetWrite(kAccessIsWrite);
527334553ec45d8982df45a6f5e656e068142ecde3fDmitry Vyukov  cur.SetAtomic(kIsAtomic);
5287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
5297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // We must not store to the trace if we do not store to the shadow.
5307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // That is, this call must be moved somewhere below.
531385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  TraceAddEvent(thr, fast_state, EventTypeMop, pc);
5327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
533334553ec45d8982df45a6f5e656e068142ecde3fDmitry Vyukov  MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
5347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      shadow_mem, cur);
5357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
5367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
5377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
5387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany                           u64 val) {
53974172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  (void)thr;
54074172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  (void)pc;
5417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (size == 0)
5427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
5437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // FIXME: fix me.
5447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  uptr offset = addr % kShadowCell;
5457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (offset) {
5467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    offset = kShadowCell - offset;
5477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (size <= offset)
5487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      return;
5497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    addr += offset;
5507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    size -= offset;
5517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
552aaac6e206453574d0130f2ae8d743f630d0c0a42Dmitry Vyukov  DCHECK_EQ(addr % 8, 0);
553aaac6e206453574d0130f2ae8d743f630d0c0a42Dmitry Vyukov  // If a user passes some insane arguments (memset(0)),
554aaac6e206453574d0130f2ae8d743f630d0c0a42Dmitry Vyukov  // let it just crash as usual.
555aaac6e206453574d0130f2ae8d743f630d0c0a42Dmitry Vyukov  if (!IsAppMem(addr) || !IsAppMem(addr + size - 1))
556aaac6e206453574d0130f2ae8d743f630d0c0a42Dmitry Vyukov    return;
55774172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  // Don't want to touch lots of shadow memory.
55874172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  // If a program maps 10MB stack, there is no need reset the whole range.
55926af89330051837bab68dcf25cf669c194b4e310Dmitry Vyukov  size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1);
56074172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  if (size < 64*1024) {
56174172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    u64 *p = (u64*)MemToShadow(addr);
56274172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    CHECK(IsShadowMem((uptr)p));
56374172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1)));
56474172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    // FIXME: may overwrite a part outside the region
56574172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    for (uptr i = 0; i < size / kShadowCell * kShadowCnt;) {
56674172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov      p[i++] = val;
56774172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov      for (uptr j = 1; j < kShadowCnt; j++)
56874172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov        p[i++] = 0;
56974172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    }
57074172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  } else {
57174172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    // The region is big, reset only beginning and end.
57274172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    const uptr kPageSize = 4096;
57374172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    u64 *begin = (u64*)MemToShadow(addr);
57474172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    u64 *end = begin + size / kShadowCell * kShadowCnt;
57574172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    u64 *p = begin;
57674172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    // Set at least first kPageSize/2 to page boundary.
57774172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    while ((p < begin + kPageSize / kShadowSize / 2) || ((uptr)p % kPageSize)) {
57874172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov      *p++ = val;
57974172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov      for (uptr j = 1; j < kShadowCnt; j++)
58074172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov        *p++ = 0;
58174172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    }
58274172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    // Reset middle part.
58374172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    u64 *p1 = p;
58474172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    p = RoundDown(end, kPageSize);
58574172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    UnmapOrDie((void*)p1, (uptr)p - (uptr)p1);
58674172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    MmapFixedNoReserve((uptr)p1, (uptr)p - (uptr)p1);
58774172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    // Set the ending.
58874172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    while (p < end) {
58974172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov      *p++ = val;
59074172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov      for (uptr j = 1; j < kShadowCnt; j++)
59174172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov        *p++ = 0;
59274172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    }
59326af89330051837bab68dcf25cf669c194b4e310Dmitry Vyukov  }
5947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
5957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
5967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size) {
5977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  MemoryRangeSet(thr, pc, addr, size, 0);
5987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
5997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
60174172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  // Processing more than 1k (4k of shadow) is expensive,
60274172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  // can cause excessive memory consumption (user does not necessary touch
60374172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  // the whole range) and most likely unnecessary.
60474172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov  if (size > 1024)
60574172de3ce25bf52d9d3918c94216f2eef5956e2Dmitry Vyukov    size = 1024;
6063285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  CHECK_EQ(thr->is_freeing, false);
6073285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  thr->is_freeing = true;
6087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  MemoryAccessRange(thr, pc, addr, size, true);
6093285866e45a8521c56ba6209daf3c9f91f844fd3Dmitry Vyukov  thr->is_freeing = false;
61046fea91f84311643cbe7c8daf70c7f81656cf3e1Dmitry Vyukov  thr->fast_state.IncrementEpoch();
61146fea91f84311643cbe7c8daf70c7f81656cf3e1Dmitry Vyukov  TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
612069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  Shadow s(thr->fast_state);
613064c84731c1cf41dcd7195c9380170b9aa6887b6Dmitry Vyukov  s.ClearIgnoreBit();
614069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  s.MarkAsFreed();
615069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  s.SetWrite(true);
616069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  s.SetAddr0AndSizeLog(0, 3);
617069ce828e3057819ee34426496ea7080f7cc52f0Dmitry Vyukov  MemoryRangeSet(thr, pc, addr, size, s.raw());
6187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
6197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
62026af89330051837bab68dcf25cf669c194b4e310Dmitry Vyukovvoid MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
62146fea91f84311643cbe7c8daf70c7f81656cf3e1Dmitry Vyukov  thr->fast_state.IncrementEpoch();
62246fea91f84311643cbe7c8daf70c7f81656cf3e1Dmitry Vyukov  TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
62326af89330051837bab68dcf25cf669c194b4e310Dmitry Vyukov  Shadow s(thr->fast_state);
624064c84731c1cf41dcd7195c9380170b9aa6887b6Dmitry Vyukov  s.ClearIgnoreBit();
62526af89330051837bab68dcf25cf669c194b4e310Dmitry Vyukov  s.SetWrite(true);
62626af89330051837bab68dcf25cf669c194b4e310Dmitry Vyukov  s.SetAddr0AndSizeLog(0, 3);
62726af89330051837bab68dcf25cf669c194b4e310Dmitry Vyukov  MemoryRangeSet(thr, pc, addr, size, s.raw());
62826af89330051837bab68dcf25cf669c194b4e310Dmitry Vyukov}
62926af89330051837bab68dcf25cf669c194b4e310Dmitry Vyukov
630d475aa8578f4a1955cdb3e3159eda8b229f8c021Kostya SerebryanyALWAYS_INLINE USED
6317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid FuncEntry(ThreadState *thr, uptr pc) {
6327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  DCHECK_EQ(thr->in_rtl, 0);
6337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StatInc(thr, StatFuncEnter);
63425d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov  DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
6357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->fast_state.IncrementEpoch();
636385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  TraceAddEvent(thr, thr->fast_state, EventTypeFuncEnter, pc);
6377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // Shadow stack maintenance can be replaced with
6397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  // stack unwinding during trace switch (which presumably must be faster).
640769544eed418993abb8efcb4ea939ed5c93a5ba2Dmitry Vyukov  DCHECK_GE(thr->shadow_stack_pos, &thr->shadow_stack[0]);
64125d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov#ifndef TSAN_GO
642769544eed418993abb8efcb4ea939ed5c93a5ba2Dmitry Vyukov  DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
64325d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov#else
64425d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov  if (thr->shadow_stack_pos == thr->shadow_stack_end) {
64525d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov    const int sz = thr->shadow_stack_end - thr->shadow_stack;
64625d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov    const int newsz = 2 * sz;
64725d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov    uptr *newstack = (uptr*)internal_alloc(MBlockShadowStack,
64825d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov        newsz * sizeof(uptr));
64925d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov    internal_memcpy(newstack, thr->shadow_stack, sz * sizeof(uptr));
65025d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov    internal_free(thr->shadow_stack);
65125d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov    thr->shadow_stack = newstack;
65225d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov    thr->shadow_stack_pos = newstack + sz;
65325d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov    thr->shadow_stack_end = newstack + newsz;
65425d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov  }
65525d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov#endif
6567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->shadow_stack_pos[0] = pc;
6577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->shadow_stack_pos++;
6587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
6597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
660d475aa8578f4a1955cdb3e3159eda8b229f8c021Kostya SerebryanyALWAYS_INLINE USED
6617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid FuncExit(ThreadState *thr) {
6627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  DCHECK_EQ(thr->in_rtl, 0);
6637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  StatInc(thr, StatFuncExit);
66425d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov  DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid());
6657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->fast_state.IncrementEpoch();
666385542a2e83a4f37de4232d6c72097c1b7d6d44bDmitry Vyukov  TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0);
6677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
668769544eed418993abb8efcb4ea939ed5c93a5ba2Dmitry Vyukov  DCHECK_GT(thr->shadow_stack_pos, &thr->shadow_stack[0]);
66925d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov#ifndef TSAN_GO
670769544eed418993abb8efcb4ea939ed5c93a5ba2Dmitry Vyukov  DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
67125d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov#endif
6727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->shadow_stack_pos--;
6737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
6747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid IgnoreCtl(ThreadState *thr, bool write, bool begin) {
6767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  DPrintf("#%d: IgnoreCtl(%d, %d)\n", thr->tid, write, begin);
6777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  thr->ignore_reads_and_writes += begin ? 1 : -1;
6787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  CHECK_GE(thr->ignore_reads_and_writes, 0);
6797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (thr->ignore_reads_and_writes)
6807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    thr->fast_state.SetIgnoreBit();
6817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  else
6827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    thr->fast_state.ClearIgnoreBit();
6837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
6847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
685b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukovbool MD5Hash::operator==(const MD5Hash &other) const {
686b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov  return hash[0] == other.hash[0] && hash[1] == other.hash[1];
687b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov}
688b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov
6897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#if TSAN_DEBUG
6907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid build_consistency_debug() {}
6917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#else
6927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid build_consistency_release() {}
6937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#endif
6947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
6957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#if TSAN_COLLECT_STATS
6967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid build_consistency_stats() {}
6977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#else
6987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid build_consistency_nostats() {}
6997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#endif
7007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
7017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#if TSAN_SHADOW_COUNT == 1
7027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid build_consistency_shadow1() {}
7037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#elif TSAN_SHADOW_COUNT == 2
7047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid build_consistency_shadow2() {}
7057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#elif TSAN_SHADOW_COUNT == 4
7067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid build_consistency_shadow4() {}
7077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#else
7087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid build_consistency_shadow8() {}
7097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#endif
7107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
7117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
7127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
713b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#ifndef TSAN_GO
7147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// Must be included in this file to make sure everything is inlined.
7157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_interface_inl.h"
716b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#endif
717