tsan_rtl.cc revision 9c4d7a4e5fc1b49757ac733fec72c5e89948fefb
1//===-- tsan_rtl.cc -------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer (TSan), a race detector.
11//
12// Main file (entry points) for the TSan run-time.
13//===----------------------------------------------------------------------===//
14
15#include "sanitizer_common/sanitizer_atomic.h"
16#include "sanitizer_common/sanitizer_common.h"
17#include "sanitizer_common/sanitizer_libc.h"
18#include "sanitizer_common/sanitizer_stackdepot.h"
19#include "sanitizer_common/sanitizer_placement_new.h"
20#include "sanitizer_common/sanitizer_symbolizer.h"
21#include "tsan_defs.h"
22#include "tsan_platform.h"
23#include "tsan_rtl.h"
24#include "tsan_mman.h"
25#include "tsan_suppressions.h"
26#include "tsan_symbolize.h"
27
28volatile int __tsan_resumed = 0;
29
30extern "C" void __tsan_resume() {
31  __tsan_resumed = 1;
32}
33
34namespace __tsan {
35
36#ifndef TSAN_GO
37THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
38#endif
39static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
40
41// Can be overriden by a front-end.
42bool CPP_WEAK OnFinalize(bool failed) {
43  return failed;
44}
45
46static Context *ctx;
47Context *CTX() {
48  return ctx;
49}
50
51static char thread_registry_placeholder[sizeof(ThreadRegistry)];
52
53static ThreadContextBase *CreateThreadContext(u32 tid) {
54  // Map thread trace when context is created.
55  MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event));
56  MapThreadTrace(GetThreadTraceHeader(tid), sizeof(Trace));
57  new(ThreadTrace(tid)) Trace();
58  void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
59  return new(mem) ThreadContext(tid);
60}
61
62#ifndef TSAN_GO
63static const u32 kThreadQuarantineSize = 16;
64#else
65static const u32 kThreadQuarantineSize = 64;
66#endif
67
68Context::Context()
69  : initialized()
70  , report_mtx(MutexTypeReport, StatMtxReport)
71  , nreported()
72  , nmissed_expected()
73  , thread_registry(new(thread_registry_placeholder) ThreadRegistry(
74      CreateThreadContext, kMaxTid, kThreadQuarantineSize))
75  , racy_stacks(MBlockRacyStacks)
76  , racy_addresses(MBlockRacyAddresses)
77  , fired_suppressions(MBlockRacyAddresses) {
78}
79
80// The objects are allocated in TLS, so one may rely on zero-initialization.
81ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
82                         uptr stk_addr, uptr stk_size,
83                         uptr tls_addr, uptr tls_size)
84  : fast_state(tid, epoch)
85  // Do not touch these, rely on zero initialization,
86  // they may be accessed before the ctor.
87  // , ignore_reads_and_writes()
88  // , in_rtl()
89  , shadow_stack_pos(&shadow_stack[0])
90#ifndef TSAN_GO
91  , jmp_bufs(MBlockJmpBuf)
92#endif
93  , tid(tid)
94  , unique_id(unique_id)
95  , stk_addr(stk_addr)
96  , stk_size(stk_size)
97  , tls_addr(tls_addr)
98  , tls_size(tls_size) {
99}
100
101static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
102  uptr n_threads;
103  uptr n_running_threads;
104  ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads);
105  InternalScopedBuffer<char> buf(4096);
106  internal_snprintf(buf.data(), buf.size(), "%d: nthr=%d nlive=%d\n",
107      i, n_threads, n_running_threads);
108  internal_write(fd, buf.data(), internal_strlen(buf.data()));
109  WriteMemoryProfile(buf.data(), buf.size());
110  internal_write(fd, buf.data(), internal_strlen(buf.data()));
111}
112
113static void BackgroundThread(void *arg) {
114  ScopedInRtl in_rtl;
115  Context *ctx = CTX();
116  const u64 kMs2Ns = 1000 * 1000;
117
118  fd_t mprof_fd = kInvalidFd;
119  if (flags()->profile_memory && flags()->profile_memory[0]) {
120    InternalScopedBuffer<char> filename(4096);
121    internal_snprintf(filename.data(), filename.size(), "%s.%d",
122        flags()->profile_memory, (int)internal_getpid());
123    uptr openrv = OpenFile(filename.data(), true);
124    if (internal_iserror(openrv)) {
125      Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
126          &filename[0]);
127    } else {
128      mprof_fd = openrv;
129    }
130  }
131
132  u64 last_flush = NanoTime();
133  for (int i = 0; ; i++) {
134    SleepForSeconds(1);
135    u64 now = NanoTime();
136
137    // Flush memory if requested.
138    if (flags()->flush_memory_ms) {
139      if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) {
140        FlushShadowMemory();
141        last_flush = NanoTime();
142      }
143    }
144
145    // Write memory profile if requested.
146    if (mprof_fd != kInvalidFd)
147      MemoryProfiler(ctx, mprof_fd, i);
148
149#ifndef TSAN_GO
150    // Flush symbolizer cache if requested.
151    if (flags()->flush_symbolizer_ms > 0) {
152      u64 last = atomic_load(&ctx->last_symbolize_time_ns,
153                             memory_order_relaxed);
154      if (last != 0 && last + flags()->flush_symbolizer_ms * kMs2Ns < now) {
155        Lock l(&ctx->report_mtx);
156        SpinMutexLock l2(&CommonSanitizerReportMutex);
157        SymbolizeFlush();
158        atomic_store(&ctx->last_symbolize_time_ns, 0, memory_order_relaxed);
159      }
160    }
161#endif
162  }
163}
164
165void DontNeedShadowFor(uptr addr, uptr size) {
166  uptr shadow_beg = MemToShadow(addr);
167  uptr shadow_end = MemToShadow(addr + size);
168  FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
169}
170
171void MapShadow(uptr addr, uptr size) {
172  MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier);
173}
174
175void MapThreadTrace(uptr addr, uptr size) {
176  DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
177  CHECK_GE(addr, kTraceMemBegin);
178  CHECK_LE(addr + size, kTraceMemBegin + kTraceMemSize);
179  if (addr != (uptr)MmapFixedNoReserve(addr, size)) {
180    Printf("FATAL: ThreadSanitizer can not mmap thread trace\n");
181    Die();
182  }
183}
184
185void Initialize(ThreadState *thr) {
186  // Thread safe because done before all threads exist.
187  static bool is_initialized = false;
188  if (is_initialized)
189    return;
190  is_initialized = true;
191  SanitizerToolName = "ThreadSanitizer";
192  // Install tool-specific callbacks in sanitizer_common.
193  SetCheckFailedCallback(TsanCheckFailed);
194
195  ScopedInRtl in_rtl;
196#ifndef TSAN_GO
197  InitializeAllocator();
198#endif
199  InitializeInterceptors();
200  const char *env = InitializePlatform();
201  InitializeMutex();
202  InitializeDynamicAnnotations();
203  ctx = new(ctx_placeholder) Context;
204#ifndef TSAN_GO
205  InitializeShadowMemory();
206#endif
207  InitializeFlags(&ctx->flags, env);
208  // Setup correct file descriptor for error reports.
209  if (internal_strcmp(flags()->log_path, "stdout") == 0)
210    __sanitizer_set_report_fd(kStdoutFd);
211  else if (internal_strcmp(flags()->log_path, "stderr") == 0)
212    __sanitizer_set_report_fd(kStderrFd);
213  else
214    __sanitizer_set_report_path(flags()->log_path);
215  InitializeSuppressions();
216#ifndef TSAN_GO
217  // Initialize external symbolizer before internal threads are started.
218  const char *external_symbolizer = flags()->external_symbolizer_path;
219  if (external_symbolizer != 0 && external_symbolizer[0] != '\0') {
220    if (!InitializeExternalSymbolizer(external_symbolizer)) {
221      Printf("Failed to start external symbolizer: '%s'\n",
222             external_symbolizer);
223      Die();
224    }
225  }
226#endif
227  internal_start_thread(&BackgroundThread, 0);
228
229  if (ctx->flags.verbosity)
230    Printf("***** Running under ThreadSanitizer v2 (pid %d) *****\n",
231           (int)internal_getpid());
232
233  // Initialize thread 0.
234  int tid = ThreadCreate(thr, 0, 0, true);
235  CHECK_EQ(tid, 0);
236  ThreadStart(thr, tid, internal_getpid());
237  CHECK_EQ(thr->in_rtl, 1);
238  ctx->initialized = true;
239
240  if (flags()->stop_on_start) {
241    Printf("ThreadSanitizer is suspended at startup (pid %d)."
242           " Call __tsan_resume().\n",
243           (int)internal_getpid());
244    while (__tsan_resumed == 0) {}
245  }
246}
247
248int Finalize(ThreadState *thr) {
249  ScopedInRtl in_rtl;
250  Context *ctx = __tsan::ctx;
251  bool failed = false;
252
253  if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1)
254    SleepForMillis(flags()->atexit_sleep_ms);
255
256  // Wait for pending reports.
257  ctx->report_mtx.Lock();
258  CommonSanitizerReportMutex.Lock();
259  CommonSanitizerReportMutex.Unlock();
260  ctx->report_mtx.Unlock();
261
262#ifndef TSAN_GO
263  if (ctx->flags.verbosity)
264    AllocatorPrintStats();
265#endif
266
267  ThreadFinalize(thr);
268
269  if (ctx->nreported) {
270    failed = true;
271#ifndef TSAN_GO
272    Printf("ThreadSanitizer: reported %d warnings\n", ctx->nreported);
273#else
274    Printf("Found %d data race(s)\n", ctx->nreported);
275#endif
276  }
277
278  if (ctx->nmissed_expected) {
279    failed = true;
280    Printf("ThreadSanitizer: missed %d expected races\n",
281        ctx->nmissed_expected);
282  }
283
284  if (flags()->print_suppressions)
285    PrintMatchedSuppressions();
286#ifndef TSAN_GO
287  if (flags()->print_benign)
288    PrintMatchedBenignRaces();
289#endif
290
291  failed = OnFinalize(failed);
292
293  StatAggregate(ctx->stat, thr->stat);
294  StatOutput(ctx->stat);
295  return failed ? flags()->exitcode : 0;
296}
297
298#ifndef TSAN_GO
299u32 CurrentStackId(ThreadState *thr, uptr pc) {
300  if (thr->shadow_stack_pos == 0)  // May happen during bootstrap.
301    return 0;
302  if (pc) {
303    thr->shadow_stack_pos[0] = pc;
304    thr->shadow_stack_pos++;
305  }
306  u32 id = StackDepotPut(thr->shadow_stack,
307                         thr->shadow_stack_pos - thr->shadow_stack);
308  if (pc)
309    thr->shadow_stack_pos--;
310  return id;
311}
312#endif
313
314void TraceSwitch(ThreadState *thr) {
315  thr->nomalloc++;
316  ScopedInRtl in_rtl;
317  Trace *thr_trace = ThreadTrace(thr->tid);
318  Lock l(&thr_trace->mtx);
319  unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts();
320  TraceHeader *hdr = &thr_trace->headers[trace];
321  hdr->epoch0 = thr->fast_state.epoch();
322  hdr->stack0.ObtainCurrent(thr, 0);
323  hdr->mset0 = thr->mset;
324  thr->nomalloc--;
325}
326
327Trace *ThreadTrace(int tid) {
328  return (Trace*)GetThreadTraceHeader(tid);
329}
330
331uptr TraceTopPC(ThreadState *thr) {
332  Event *events = (Event*)GetThreadTrace(thr->tid);
333  uptr pc = events[thr->fast_state.GetTracePos()];
334  return pc;
335}
336
337uptr TraceSize() {
338  return (uptr)(1ull << (kTracePartSizeBits + flags()->history_size + 1));
339}
340
341uptr TraceParts() {
342  return TraceSize() / kTracePartSize;
343}
344
345#ifndef TSAN_GO
346extern "C" void __tsan_trace_switch() {
347  TraceSwitch(cur_thread());
348}
349
350extern "C" void __tsan_report_race() {
351  ReportRace(cur_thread());
352}
353#endif
354
355ALWAYS_INLINE
356Shadow LoadShadow(u64 *p) {
357  u64 raw = atomic_load((atomic_uint64_t*)p, memory_order_relaxed);
358  return Shadow(raw);
359}
360
361ALWAYS_INLINE
362void StoreShadow(u64 *sp, u64 s) {
363  atomic_store((atomic_uint64_t*)sp, s, memory_order_relaxed);
364}
365
366ALWAYS_INLINE
367void StoreIfNotYetStored(u64 *sp, u64 *s) {
368  StoreShadow(sp, *s);
369  *s = 0;
370}
371
372static inline void HandleRace(ThreadState *thr, u64 *shadow_mem,
373                              Shadow cur, Shadow old) {
374  thr->racy_state[0] = cur.raw();
375  thr->racy_state[1] = old.raw();
376  thr->racy_shadow_addr = shadow_mem;
377#ifndef TSAN_GO
378  HACKY_CALL(__tsan_report_race);
379#else
380  ReportRace(thr);
381#endif
382}
383
384static inline bool OldIsInSameSynchEpoch(Shadow old, ThreadState *thr) {
385  return old.epoch() >= thr->fast_synch_epoch;
386}
387
388static inline bool HappensBefore(Shadow old, ThreadState *thr) {
389  return thr->clock.get(old.TidWithIgnore()) >= old.epoch();
390}
391
392ALWAYS_INLINE USED
393void MemoryAccessImpl(ThreadState *thr, uptr addr,
394    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
395    u64 *shadow_mem, Shadow cur) {
396  StatInc(thr, StatMop);
397  StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
398  StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
399
400  // This potentially can live in an MMX/SSE scratch register.
401  // The required intrinsics are:
402  // __m128i _mm_move_epi64(__m128i*);
403  // _mm_storel_epi64(u64*, __m128i);
404  u64 store_word = cur.raw();
405
406  // scan all the shadow values and dispatch to 4 categories:
407  // same, replace, candidate and race (see comments below).
408  // we consider only 3 cases regarding access sizes:
409  // equal, intersect and not intersect. initially I considered
410  // larger and smaller as well, it allowed to replace some
411  // 'candidates' with 'same' or 'replace', but I think
412  // it's just not worth it (performance- and complexity-wise).
413
414  Shadow old(0);
415  if (kShadowCnt == 1) {
416    int idx = 0;
417#include "tsan_update_shadow_word_inl.h"
418  } else if (kShadowCnt == 2) {
419    int idx = 0;
420#include "tsan_update_shadow_word_inl.h"
421    idx = 1;
422#include "tsan_update_shadow_word_inl.h"
423  } else if (kShadowCnt == 4) {
424    int idx = 0;
425#include "tsan_update_shadow_word_inl.h"
426    idx = 1;
427#include "tsan_update_shadow_word_inl.h"
428    idx = 2;
429#include "tsan_update_shadow_word_inl.h"
430    idx = 3;
431#include "tsan_update_shadow_word_inl.h"
432  } else if (kShadowCnt == 8) {
433    int idx = 0;
434#include "tsan_update_shadow_word_inl.h"
435    idx = 1;
436#include "tsan_update_shadow_word_inl.h"
437    idx = 2;
438#include "tsan_update_shadow_word_inl.h"
439    idx = 3;
440#include "tsan_update_shadow_word_inl.h"
441    idx = 4;
442#include "tsan_update_shadow_word_inl.h"
443    idx = 5;
444#include "tsan_update_shadow_word_inl.h"
445    idx = 6;
446#include "tsan_update_shadow_word_inl.h"
447    idx = 7;
448#include "tsan_update_shadow_word_inl.h"
449  } else {
450    CHECK(false);
451  }
452
453  // we did not find any races and had already stored
454  // the current access info, so we are done
455  if (LIKELY(store_word == 0))
456    return;
457  // choose a random candidate slot and replace it
458  StoreShadow(shadow_mem + (cur.epoch() % kShadowCnt), store_word);
459  StatInc(thr, StatShadowReplace);
460  return;
461 RACE:
462  HandleRace(thr, shadow_mem, cur, old);
463  return;
464}
465
466void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
467    int size, bool kAccessIsWrite, bool kIsAtomic) {
468  while (size) {
469    int size1 = 1;
470    int kAccessSizeLog = kSizeLog1;
471    if (size >= 8 && (addr & ~7) == ((addr + 8) & ~7)) {
472      size1 = 8;
473      kAccessSizeLog = kSizeLog8;
474    } else if (size >= 4 && (addr & ~7) == ((addr + 4) & ~7)) {
475      size1 = 4;
476      kAccessSizeLog = kSizeLog4;
477    } else if (size >= 2 && (addr & ~7) == ((addr + 2) & ~7)) {
478      size1 = 2;
479      kAccessSizeLog = kSizeLog2;
480    }
481    MemoryAccess(thr, pc, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic);
482    addr += size1;
483    size -= size1;
484  }
485}
486
487ALWAYS_INLINE USED
488void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
489    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {
490  u64 *shadow_mem = (u64*)MemToShadow(addr);
491  DPrintf2("#%d: MemoryAccess: @%p %p size=%d"
492      " is_write=%d shadow_mem=%p {%zx, %zx, %zx, %zx}\n",
493      (int)thr->fast_state.tid(), (void*)pc, (void*)addr,
494      (int)(1 << kAccessSizeLog), kAccessIsWrite, shadow_mem,
495      (uptr)shadow_mem[0], (uptr)shadow_mem[1],
496      (uptr)shadow_mem[2], (uptr)shadow_mem[3]);
497#if TSAN_DEBUG
498  if (!IsAppMem(addr)) {
499    Printf("Access to non app mem %zx\n", addr);
500    DCHECK(IsAppMem(addr));
501  }
502  if (!IsShadowMem((uptr)shadow_mem)) {
503    Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
504    DCHECK(IsShadowMem((uptr)shadow_mem));
505  }
506#endif
507
508  if (*shadow_mem == kShadowRodata) {
509    // Access to .rodata section, no races here.
510    // Measurements show that it can be 10-20% of all memory accesses.
511    StatInc(thr, StatMop);
512    StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
513    StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
514    StatInc(thr, StatMopRodata);
515    return;
516  }
517
518  FastState fast_state = thr->fast_state;
519  if (fast_state.GetIgnoreBit())
520    return;
521  fast_state.IncrementEpoch();
522  thr->fast_state = fast_state;
523  Shadow cur(fast_state);
524  cur.SetAddr0AndSizeLog(addr & 7, kAccessSizeLog);
525  cur.SetWrite(kAccessIsWrite);
526  cur.SetAtomic(kIsAtomic);
527
528  // We must not store to the trace if we do not store to the shadow.
529  // That is, this call must be moved somewhere below.
530  TraceAddEvent(thr, fast_state, EventTypeMop, pc);
531
532  MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
533      shadow_mem, cur);
534}
535
536static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
537                           u64 val) {
538  (void)thr;
539  (void)pc;
540  if (size == 0)
541    return;
542  // FIXME: fix me.
543  uptr offset = addr % kShadowCell;
544  if (offset) {
545    offset = kShadowCell - offset;
546    if (size <= offset)
547      return;
548    addr += offset;
549    size -= offset;
550  }
551  DCHECK_EQ(addr % 8, 0);
552  // If a user passes some insane arguments (memset(0)),
553  // let it just crash as usual.
554  if (!IsAppMem(addr) || !IsAppMem(addr + size - 1))
555    return;
556  // Don't want to touch lots of shadow memory.
557  // If a program maps 10MB stack, there is no need reset the whole range.
558  size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1);
559  // UnmapOrDie/MmapFixedNoReserve does not work on Windows,
560  // so we do it only for C/C++.
561  if (kGoMode || size < 64*1024) {
562    u64 *p = (u64*)MemToShadow(addr);
563    CHECK(IsShadowMem((uptr)p));
564    CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1)));
565    // FIXME: may overwrite a part outside the region
566    for (uptr i = 0; i < size / kShadowCell * kShadowCnt;) {
567      p[i++] = val;
568      for (uptr j = 1; j < kShadowCnt; j++)
569        p[i++] = 0;
570    }
571  } else {
572    // The region is big, reset only beginning and end.
573    const uptr kPageSize = 4096;
574    u64 *begin = (u64*)MemToShadow(addr);
575    u64 *end = begin + size / kShadowCell * kShadowCnt;
576    u64 *p = begin;
577    // Set at least first kPageSize/2 to page boundary.
578    while ((p < begin + kPageSize / kShadowSize / 2) || ((uptr)p % kPageSize)) {
579      *p++ = val;
580      for (uptr j = 1; j < kShadowCnt; j++)
581        *p++ = 0;
582    }
583    // Reset middle part.
584    u64 *p1 = p;
585    p = RoundDown(end, kPageSize);
586    UnmapOrDie((void*)p1, (uptr)p - (uptr)p1);
587    MmapFixedNoReserve((uptr)p1, (uptr)p - (uptr)p1);
588    // Set the ending.
589    while (p < end) {
590      *p++ = val;
591      for (uptr j = 1; j < kShadowCnt; j++)
592        *p++ = 0;
593    }
594  }
595}
596
597void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size) {
598  MemoryRangeSet(thr, pc, addr, size, 0);
599}
600
601void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
602  // Processing more than 1k (4k of shadow) is expensive,
603  // can cause excessive memory consumption (user does not necessary touch
604  // the whole range) and most likely unnecessary.
605  if (size > 1024)
606    size = 1024;
607  CHECK_EQ(thr->is_freeing, false);
608  thr->is_freeing = true;
609  MemoryAccessRange(thr, pc, addr, size, true);
610  thr->is_freeing = false;
611  thr->fast_state.IncrementEpoch();
612  TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
613  Shadow s(thr->fast_state);
614  s.ClearIgnoreBit();
615  s.MarkAsFreed();
616  s.SetWrite(true);
617  s.SetAddr0AndSizeLog(0, 3);
618  MemoryRangeSet(thr, pc, addr, size, s.raw());
619}
620
621void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
622  thr->fast_state.IncrementEpoch();
623  TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
624  Shadow s(thr->fast_state);
625  s.ClearIgnoreBit();
626  s.SetWrite(true);
627  s.SetAddr0AndSizeLog(0, 3);
628  MemoryRangeSet(thr, pc, addr, size, s.raw());
629}
630
631ALWAYS_INLINE USED
632void FuncEntry(ThreadState *thr, uptr pc) {
633  DCHECK_EQ(thr->in_rtl, 0);
634  StatInc(thr, StatFuncEnter);
635  DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
636  thr->fast_state.IncrementEpoch();
637  TraceAddEvent(thr, thr->fast_state, EventTypeFuncEnter, pc);
638
639  // Shadow stack maintenance can be replaced with
640  // stack unwinding during trace switch (which presumably must be faster).
641  DCHECK_GE(thr->shadow_stack_pos, &thr->shadow_stack[0]);
642#ifndef TSAN_GO
643  DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
644#else
645  if (thr->shadow_stack_pos == thr->shadow_stack_end) {
646    const int sz = thr->shadow_stack_end - thr->shadow_stack;
647    const int newsz = 2 * sz;
648    uptr *newstack = (uptr*)internal_alloc(MBlockShadowStack,
649        newsz * sizeof(uptr));
650    internal_memcpy(newstack, thr->shadow_stack, sz * sizeof(uptr));
651    internal_free(thr->shadow_stack);
652    thr->shadow_stack = newstack;
653    thr->shadow_stack_pos = newstack + sz;
654    thr->shadow_stack_end = newstack + newsz;
655  }
656#endif
657  thr->shadow_stack_pos[0] = pc;
658  thr->shadow_stack_pos++;
659}
660
661ALWAYS_INLINE USED
662void FuncExit(ThreadState *thr) {
663  DCHECK_EQ(thr->in_rtl, 0);
664  StatInc(thr, StatFuncExit);
665  DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid());
666  thr->fast_state.IncrementEpoch();
667  TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0);
668
669  DCHECK_GT(thr->shadow_stack_pos, &thr->shadow_stack[0]);
670#ifndef TSAN_GO
671  DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
672#endif
673  thr->shadow_stack_pos--;
674}
675
676void IgnoreCtl(ThreadState *thr, bool write, bool begin) {
677  DPrintf("#%d: IgnoreCtl(%d, %d)\n", thr->tid, write, begin);
678  thr->ignore_reads_and_writes += begin ? 1 : -1;
679  CHECK_GE(thr->ignore_reads_and_writes, 0);
680  if (thr->ignore_reads_and_writes)
681    thr->fast_state.SetIgnoreBit();
682  else
683    thr->fast_state.ClearIgnoreBit();
684}
685
686bool MD5Hash::operator==(const MD5Hash &other) const {
687  return hash[0] == other.hash[0] && hash[1] == other.hash[1];
688}
689
690#if TSAN_DEBUG
691void build_consistency_debug() {}
692#else
693void build_consistency_release() {}
694#endif
695
696#if TSAN_COLLECT_STATS
697void build_consistency_stats() {}
698#else
699void build_consistency_nostats() {}
700#endif
701
702#if TSAN_SHADOW_COUNT == 1
703void build_consistency_shadow1() {}
704#elif TSAN_SHADOW_COUNT == 2
705void build_consistency_shadow2() {}
706#elif TSAN_SHADOW_COUNT == 4
707void build_consistency_shadow4() {}
708#else
709void build_consistency_shadow8() {}
710#endif
711
712}  // namespace __tsan
713
714#ifndef TSAN_GO
715// Must be included in this file to make sure everything is inlined.
716#include "tsan_interface_inl.h"
717#endif
718