1 //===-- tsan_rtl.h ----------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //
11 // Main internal TSan header file.
12 //
13 // Ground rules:
14 // - C++ run-time should not be used (static CTORs, RTTI, exceptions, static
15 // function-scope locals)
16 // - All functions/classes/etc reside in namespace __tsan, except for those
17 // declared in tsan_interface.h.
18 // - Platform-specific files should be used instead of ifdefs (*).
19 // - No system headers included in header files (*).
20 // - Platform specific headres included only into platform-specific files (*).
21 //
22 // (*) Except when inlining is critical for performance.
23 //===----------------------------------------------------------------------===//
24
25 #ifndef TSAN_RTL_H
26 #define TSAN_RTL_H
27
28 #include "sanitizer_common/sanitizer_allocator.h"
29 #include "sanitizer_common/sanitizer_allocator_internal.h"
30 #include "sanitizer_common/sanitizer_asm.h"
31 #include "sanitizer_common/sanitizer_common.h"
32 #include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
33 #include "sanitizer_common/sanitizer_libignore.h"
34 #include "sanitizer_common/sanitizer_suppressions.h"
35 #include "sanitizer_common/sanitizer_thread_registry.h"
36 #include "sanitizer_common/sanitizer_vector.h"
37 #include "tsan_defs.h"
38 #include "tsan_flags.h"
39 #include "tsan_ignoreset.h"
40 #include "tsan_ilist.h"
41 #include "tsan_mman.h"
42 #include "tsan_mutexset.h"
43 #include "tsan_platform.h"
44 #include "tsan_report.h"
45 #include "tsan_shadow.h"
46 #include "tsan_stack_trace.h"
47 #include "tsan_sync.h"
48 #include "tsan_trace.h"
49 #include "tsan_vector_clock.h"
50
51 #if SANITIZER_WORDSIZE != 64
52 # error "ThreadSanitizer is supported only on 64-bit platforms"
53 #endif
54
55 namespace __tsan {
56
57 extern bool ready_to_symbolize;
58
59 #if !SANITIZER_GO
60 struct MapUnmapCallback;
61 # if defined(__mips64) || defined(__aarch64__) || defined(__loongarch__) || \
62 defined(__powerpc__) || SANITIZER_RISCV64
63
64 struct AP32 {
65 static const uptr kSpaceBeg = SANITIZER_MMAP_BEGIN;
66 static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
67 static const uptr kMetadataSize = 0;
68 typedef __sanitizer::CompactSizeClassMap SizeClassMap;
69 static const uptr kRegionSizeLog = 20;
70 using AddressSpaceView = LocalAddressSpaceView;
71 typedef __tsan::MapUnmapCallback MapUnmapCallback;
72 static const uptr kFlags = 0;
73 };
74 typedef SizeClassAllocator32<AP32> PrimaryAllocator;
75 #else
76 struct AP64 { // Allocator64 parameters. Deliberately using a short name.
77 # if defined(__s390x__)
78 typedef MappingS390x Mapping;
79 # else
80 typedef Mapping48AddressSpace Mapping;
81 # endif
82 static const uptr kSpaceBeg = Mapping::kHeapMemBeg;
83 static const uptr kSpaceSize = Mapping::kHeapMemEnd - Mapping::kHeapMemBeg;
84 static const uptr kMetadataSize = 0;
85 typedef DefaultSizeClassMap SizeClassMap;
86 typedef __tsan::MapUnmapCallback MapUnmapCallback;
87 static const uptr kFlags = 0;
88 using AddressSpaceView = LocalAddressSpaceView;
89 };
90 typedef SizeClassAllocator64<AP64> PrimaryAllocator;
91 #endif
92 typedef CombinedAllocator<PrimaryAllocator> Allocator;
93 typedef Allocator::AllocatorCache AllocatorCache;
94 Allocator *allocator();
95 #endif
96
97 struct ThreadSignalContext;
98
99 struct JmpBuf {
100 uptr sp;
101 int int_signal_send;
102 bool in_blocking_func;
103 uptr oldset_stack_size;
104 uptr in_signal_handler;
105 uptr *shadow_stack_pos;
106 };
107
108 // A Processor represents a physical thread, or a P for Go.
109 // It is used to store internal resources like allocate cache, and does not
110 // participate in race-detection logic (invisible to end user).
111 // In C++ it is tied to an OS thread just like ThreadState, however ideally
112 // it should be tied to a CPU (this way we will have fewer allocator caches).
113 // In Go it is tied to a P, so there are significantly fewer Processor's than
114 // ThreadState's (which are tied to Gs).
115 // A ThreadState must be wired with a Processor to handle events.
116 struct Processor {
117 ThreadState *thr; // currently wired thread, or nullptr
118 #if !SANITIZER_GO
119 AllocatorCache alloc_cache;
120 InternalAllocatorCache internal_alloc_cache;
121 #endif
122 DenseSlabAllocCache block_cache;
123 DenseSlabAllocCache sync_cache;
124 DDPhysicalThread *dd_pt;
125 };
126
127 #if !SANITIZER_GO
128 // ScopedGlobalProcessor temporary setups a global processor for the current
129 // thread, if it does not have one. Intended for interceptors that can run
130 // at the very thread end, when we already destroyed the thread processor.
131 struct ScopedGlobalProcessor {
132 ScopedGlobalProcessor();
133 ~ScopedGlobalProcessor();
134 };
135 #endif
136
137 struct TidEpoch {
138 Tid tid;
139 Epoch epoch;
140 };
141
142 struct alignas(SANITIZER_CACHE_LINE_SIZE) TidSlot {
143 Mutex mtx;
144 Sid sid;
145 atomic_uint32_t raw_epoch;
146 ThreadState *thr;
147 Vector<TidEpoch> journal;
148 INode node;
149
epochTidSlot150 Epoch epoch() const {
151 return static_cast<Epoch>(atomic_load(&raw_epoch, memory_order_relaxed));
152 }
153
SetEpochTidSlot154 void SetEpoch(Epoch v) {
155 atomic_store(&raw_epoch, static_cast<u32>(v), memory_order_relaxed);
156 }
157
158 TidSlot();
159 };
160
161 // This struct is stored in TLS.
162 struct alignas(SANITIZER_CACHE_LINE_SIZE) ThreadState {
163 FastState fast_state;
164 int ignore_sync;
165 #if !SANITIZER_GO
166 int ignore_interceptors;
167 #endif
168 uptr *shadow_stack_pos;
169
170 // Current position in tctx->trace.Back()->events (Event*).
171 atomic_uintptr_t trace_pos;
172 // PC of the last memory access, used to compute PC deltas in the trace.
173 uptr trace_prev_pc;
174
175 // Technically `current` should be a separate THREADLOCAL variable;
176 // but it is placed here in order to share cache line with previous fields.
177 ThreadState* current;
178
179 atomic_sint32_t pending_signals;
180
181 VectorClock clock;
182
183 // This is a slow path flag. On fast path, fast_state.GetIgnoreBit() is read.
184 // We do not distinguish beteween ignoring reads and writes
185 // for better performance.
186 int ignore_reads_and_writes;
187 int suppress_reports;
188 // Go does not support ignores.
189 #if !SANITIZER_GO
190 IgnoreSet mop_ignore_set;
191 IgnoreSet sync_ignore_set;
192 #endif
193 uptr *shadow_stack;
194 uptr *shadow_stack_end;
195 #if !SANITIZER_GO
196 Vector<JmpBuf> jmp_bufs;
197 int in_symbolizer;
198 atomic_uintptr_t in_blocking_func;
199 bool in_ignored_lib;
200 bool is_inited;
201 #endif
202 MutexSet mset;
203 bool is_dead;
204 const Tid tid;
205 uptr stk_addr;
206 uptr stk_size;
207 uptr tls_addr;
208 uptr tls_size;
209 ThreadContext *tctx;
210
211 DDLogicalThread *dd_lt;
212
213 TidSlot *slot;
214 uptr slot_epoch;
215 bool slot_locked;
216
217 // Current wired Processor, or nullptr. Required to handle any events.
218 Processor *proc1;
219 #if !SANITIZER_GO
procThreadState220 Processor *proc() { return proc1; }
221 #else
222 Processor *proc();
223 #endif
224
225 atomic_uintptr_t in_signal_handler;
226 atomic_uintptr_t signal_ctx;
227
228 #if !SANITIZER_GO
229 StackID last_sleep_stack_id;
230 VectorClock last_sleep_clock;
231 #endif
232
233 // Set in regions of runtime that must be signal-safe and fork-safe.
234 // If set, malloc must not be called.
235 int nomalloc;
236
237 const ReportDesc *current_report;
238
239 explicit ThreadState(Tid tid);
240 };
241
242 #if !SANITIZER_GO
243 #if SANITIZER_APPLE || SANITIZER_ANDROID
244 ThreadState *cur_thread();
245 void set_cur_thread(ThreadState *thr);
246 void cur_thread_finalize();
cur_thread_init()247 inline ThreadState *cur_thread_init() { return cur_thread(); }
248 # else
249 __attribute__((tls_model("initial-exec")))
250 extern THREADLOCAL char cur_thread_placeholder[];
cur_thread()251 inline ThreadState *cur_thread() {
252 return reinterpret_cast<ThreadState *>(cur_thread_placeholder)->current;
253 }
cur_thread_init()254 inline ThreadState *cur_thread_init() {
255 ThreadState *thr = reinterpret_cast<ThreadState *>(cur_thread_placeholder);
256 if (UNLIKELY(!thr->current))
257 thr->current = thr;
258 return thr->current;
259 }
set_cur_thread(ThreadState * thr)260 inline void set_cur_thread(ThreadState *thr) {
261 reinterpret_cast<ThreadState *>(cur_thread_placeholder)->current = thr;
262 }
cur_thread_finalize()263 inline void cur_thread_finalize() { }
264 # endif // SANITIZER_APPLE || SANITIZER_ANDROID
265 #endif // SANITIZER_GO
266
267 class ThreadContext final : public ThreadContextBase {
268 public:
269 explicit ThreadContext(Tid tid);
270 ~ThreadContext();
271 ThreadState *thr;
272 StackID creation_stack_id;
273 VectorClock *sync;
274 uptr sync_epoch;
275 Trace trace;
276
277 // Override superclass callbacks.
278 void OnDead() override;
279 void OnJoined(void *arg) override;
280 void OnFinished() override;
281 void OnStarted(void *arg) override;
282 void OnCreated(void *arg) override;
283 void OnReset() override;
284 void OnDetached(void *arg) override;
285 };
286
287 struct RacyStacks {
288 MD5Hash hash[2];
289 bool operator==(const RacyStacks &other) const;
290 };
291
292 struct RacyAddress {
293 uptr addr_min;
294 uptr addr_max;
295 };
296
297 struct FiredSuppression {
298 ReportType type;
299 uptr pc_or_addr;
300 Suppression *supp;
301 };
302
303 struct Context {
304 Context();
305
306 bool initialized;
307 #if !SANITIZER_GO
308 bool after_multithreaded_fork;
309 #endif
310
311 MetaMap metamap;
312
313 Mutex report_mtx;
314 int nreported;
315 atomic_uint64_t last_symbolize_time_ns;
316
317 void *background_thread;
318 atomic_uint32_t stop_background_thread;
319
320 ThreadRegistry thread_registry;
321
322 // This is used to prevent a very unlikely but very pathological behavior.
323 // Since memory access handling is not synchronized with DoReset,
324 // a thread running concurrently with DoReset can leave a bogus shadow value
325 // that will be later falsely detected as a race. For such false races
326 // RestoreStack will return false and we will not report it.
327 // However, consider that a thread leaves a whole lot of such bogus values
328 // and these values are later read by a whole lot of threads.
329 // This will cause massive amounts of ReportRace calls and lots of
330 // serialization. In very pathological cases the resulting slowdown
331 // can be >100x. This is very unlikely, but it was presumably observed
332 // in practice: https://github.com/google/sanitizers/issues/1552
333 // If this happens, previous access sid+epoch will be the same for all of
334 // these false races b/c if the thread will try to increment epoch, it will
335 // notice that DoReset has happened and will stop producing bogus shadow
336 // values. So, last_spurious_race is used to remember the last sid+epoch
337 // for which RestoreStack returned false. Then it is used to filter out
338 // races with the same sid+epoch very early and quickly.
339 // It is of course possible that multiple threads left multiple bogus shadow
340 // values and all of them are read by lots of threads at the same time.
341 // In such case last_spurious_race will only be able to deduplicate a few
342 // races from one thread, then few from another and so on. An alternative
343 // would be to hold an array of such sid+epoch, but we consider such scenario
344 // as even less likely.
345 // Note: this can lead to some rare false negatives as well:
346 // 1. When a legit access with the same sid+epoch participates in a race
347 // as the "previous" memory access, it will be wrongly filtered out.
348 // 2. When RestoreStack returns false for a legit memory access because it
349 // was already evicted from the thread trace, we will still remember it in
350 // last_spurious_race. Then if there is another racing memory access from
351 // the same thread that happened in the same epoch, but was stored in the
352 // next thread trace part (which is still preserved in the thread trace),
353 // we will also wrongly filter it out while RestoreStack would actually
354 // succeed for that second memory access.
355 RawShadow last_spurious_race;
356
357 Mutex racy_mtx;
358 Vector<RacyStacks> racy_stacks;
359 // Number of fired suppressions may be large enough.
360 Mutex fired_suppressions_mtx;
361 InternalMmapVector<FiredSuppression> fired_suppressions;
362 DDetector *dd;
363
364 Flags flags;
365 fd_t memprof_fd;
366
367 // The last slot index (kFreeSid) is used to denote freed memory.
368 TidSlot slots[kThreadSlotCount - 1];
369
370 // Protects global_epoch, slot_queue, trace_part_recycle.
371 Mutex slot_mtx;
372 uptr global_epoch; // guarded by slot_mtx and by all slot mutexes
373 bool resetting; // global reset is in progress
374 IList<TidSlot, &TidSlot::node> slot_queue SANITIZER_GUARDED_BY(slot_mtx);
375 IList<TraceHeader, &TraceHeader::global, TracePart> trace_part_recycle
376 SANITIZER_GUARDED_BY(slot_mtx);
377 uptr trace_part_total_allocated SANITIZER_GUARDED_BY(slot_mtx);
378 uptr trace_part_recycle_finished SANITIZER_GUARDED_BY(slot_mtx);
379 uptr trace_part_finished_excess SANITIZER_GUARDED_BY(slot_mtx);
380 #if SANITIZER_GO
381 uptr mapped_shadow_begin;
382 uptr mapped_shadow_end;
383 #endif
384 };
385
386 extern Context *ctx; // The one and the only global runtime context.
387
flags()388 ALWAYS_INLINE Flags *flags() {
389 return &ctx->flags;
390 }
391
392 struct ScopedIgnoreInterceptors {
ScopedIgnoreInterceptorsScopedIgnoreInterceptors393 ScopedIgnoreInterceptors() {
394 #if !SANITIZER_GO
395 cur_thread()->ignore_interceptors++;
396 #endif
397 }
398
~ScopedIgnoreInterceptorsScopedIgnoreInterceptors399 ~ScopedIgnoreInterceptors() {
400 #if !SANITIZER_GO
401 cur_thread()->ignore_interceptors--;
402 #endif
403 }
404 };
405
406 const char *GetObjectTypeFromTag(uptr tag);
407 const char *GetReportHeaderFromTag(uptr tag);
408 uptr TagFromShadowStackFrame(uptr pc);
409
410 class ScopedReportBase {
411 public:
412 void AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, Tid tid,
413 StackTrace stack, const MutexSet *mset);
414 void AddStack(StackTrace stack, bool suppressable = false);
415 void AddThread(const ThreadContext *tctx, bool suppressable = false);
416 void AddThread(Tid tid, bool suppressable = false);
417 void AddUniqueTid(Tid unique_tid);
418 int AddMutex(uptr addr, StackID creation_stack_id);
419 void AddLocation(uptr addr, uptr size);
420 void AddSleep(StackID stack_id);
421 void SetCount(int count);
422 void SetSigNum(int sig);
423
424 const ReportDesc *GetReport() const;
425
426 protected:
427 ScopedReportBase(ReportType typ, uptr tag);
428 ~ScopedReportBase();
429
430 private:
431 ReportDesc *rep_;
432 // Symbolizer makes lots of intercepted calls. If we try to process them,
433 // at best it will cause deadlocks on internal mutexes.
434 ScopedIgnoreInterceptors ignore_interceptors_;
435
436 ScopedReportBase(const ScopedReportBase &) = delete;
437 void operator=(const ScopedReportBase &) = delete;
438 };
439
440 class ScopedReport : public ScopedReportBase {
441 public:
442 explicit ScopedReport(ReportType typ, uptr tag = kExternalTagNone);
443 ~ScopedReport();
444
445 private:
446 ScopedErrorReportLock lock_;
447 };
448
449 bool ShouldReport(ThreadState *thr, ReportType typ);
450 ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
451
452 // The stack could look like:
453 // <start> | <main> | <foo> | tag | <bar>
454 // This will extract the tag and keep:
455 // <start> | <main> | <foo> | <bar>
456 template<typename StackTraceTy>
457 void ExtractTagFromStack(StackTraceTy *stack, uptr *tag = nullptr) {
458 if (stack->size < 2) return;
459 uptr possible_tag_pc = stack->trace[stack->size - 2];
460 uptr possible_tag = TagFromShadowStackFrame(possible_tag_pc);
461 if (possible_tag == kExternalTagNone) return;
462 stack->trace_buffer[stack->size - 2] = stack->trace_buffer[stack->size - 1];
463 stack->size -= 1;
464 if (tag) *tag = possible_tag;
465 }
466
467 template<typename StackTraceTy>
468 void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack,
469 uptr *tag = nullptr) {
470 uptr size = thr->shadow_stack_pos - thr->shadow_stack;
471 uptr start = 0;
472 if (size + !!toppc > kStackTraceMax) {
473 start = size + !!toppc - kStackTraceMax;
474 size = kStackTraceMax - !!toppc;
475 }
476 stack->Init(&thr->shadow_stack[start], size, toppc);
477 ExtractTagFromStack(stack, tag);
478 }
479
480 #define GET_STACK_TRACE_FATAL(thr, pc) \
481 VarSizeStackTrace stack; \
482 ObtainCurrentStack(thr, pc, &stack); \
483 stack.ReverseOrder();
484
485 void MapShadow(uptr addr, uptr size);
486 void MapThreadTrace(uptr addr, uptr size, const char *name);
487 void DontNeedShadowFor(uptr addr, uptr size);
488 void UnmapShadow(ThreadState *thr, uptr addr, uptr size);
489 void InitializeShadowMemory();
490 void DontDumpShadow(uptr addr, uptr size);
491 void InitializeInterceptors();
492 void InitializeLibIgnore();
493 void InitializeDynamicAnnotations();
494
495 void ForkBefore(ThreadState *thr, uptr pc);
496 void ForkParentAfter(ThreadState *thr, uptr pc);
497 void ForkChildAfter(ThreadState *thr, uptr pc, bool start_thread);
498
499 void ReportRace(ThreadState *thr, RawShadow *shadow_mem, Shadow cur, Shadow old,
500 AccessType typ);
501 bool OutputReport(ThreadState *thr, const ScopedReport &srep);
502 bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace);
503 bool IsExpectedReport(uptr addr, uptr size);
504
505 #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
506 # define DPrintf Printf
507 #else
508 # define DPrintf(...)
509 #endif
510
511 #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 2
512 # define DPrintf2 Printf
513 #else
514 # define DPrintf2(...)
515 #endif
516
517 StackID CurrentStackId(ThreadState *thr, uptr pc);
518 ReportStack *SymbolizeStackId(StackID stack_id);
519 void PrintCurrentStack(ThreadState *thr, uptr pc);
520 void PrintCurrentStack(uptr pc, bool fast); // may uses libunwind
521 MBlock *JavaHeapBlock(uptr addr, uptr *start);
522
523 void Initialize(ThreadState *thr);
524 void MaybeSpawnBackgroundThread();
525 int Finalize(ThreadState *thr);
526
527 void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write);
528 void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write);
529
530 void MemoryAccess(ThreadState *thr, uptr pc, uptr addr, uptr size,
531 AccessType typ);
532 void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr, uptr size,
533 AccessType typ);
534 // This creates 2 non-inlined specialized versions of MemoryAccessRange.
535 template <bool is_read>
536 void MemoryAccessRangeT(ThreadState *thr, uptr pc, uptr addr, uptr size);
537
538 ALWAYS_INLINE
MemoryAccessRange(ThreadState * thr,uptr pc,uptr addr,uptr size,bool is_write)539 void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, uptr size,
540 bool is_write) {
541 if (size == 0)
542 return;
543 if (is_write)
544 MemoryAccessRangeT<false>(thr, pc, addr, size);
545 else
546 MemoryAccessRangeT<true>(thr, pc, addr, size);
547 }
548
549 void ShadowSet(RawShadow *p, RawShadow *end, RawShadow v);
550 void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size);
551 void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size);
552 void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size);
553 void MemoryRangeImitateWriteOrResetRange(ThreadState *thr, uptr pc, uptr addr,
554 uptr size);
555
556 void ThreadIgnoreBegin(ThreadState *thr, uptr pc);
557 void ThreadIgnoreEnd(ThreadState *thr);
558 void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc);
559 void ThreadIgnoreSyncEnd(ThreadState *thr);
560
561 Tid ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached);
562 void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id,
563 ThreadType thread_type);
564 void ThreadFinish(ThreadState *thr);
565 Tid ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid);
566 void ThreadJoin(ThreadState *thr, uptr pc, Tid tid);
567 void ThreadDetach(ThreadState *thr, uptr pc, Tid tid);
568 void ThreadFinalize(ThreadState *thr);
569 void ThreadSetName(ThreadState *thr, const char *name);
570 int ThreadCount(ThreadState *thr);
571 void ProcessPendingSignalsImpl(ThreadState *thr);
572 void ThreadNotJoined(ThreadState *thr, uptr pc, Tid tid, uptr uid);
573
574 Processor *ProcCreate();
575 void ProcDestroy(Processor *proc);
576 void ProcWire(Processor *proc, ThreadState *thr);
577 void ProcUnwire(Processor *proc, ThreadState *thr);
578
579 // Note: the parameter is called flagz, because flags is already taken
580 // by the global function that returns flags.
581 void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
582 void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
583 void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
584 void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0,
585 int rec = 1);
586 int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
587 void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
588 void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
589 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
590 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
591 void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD
592 void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr);
593
594 void Acquire(ThreadState *thr, uptr pc, uptr addr);
595 // AcquireGlobal synchronizes the current thread with all other threads.
596 // In terms of happens-before relation, it draws a HB edge from all threads
597 // (where they happen to execute right now) to the current thread. We use it to
598 // handle Go finalizers. Namely, finalizer goroutine executes AcquireGlobal
599 // right before executing finalizers. This provides a coarse, but simple
600 // approximation of the actual required synchronization.
601 void AcquireGlobal(ThreadState *thr);
602 void Release(ThreadState *thr, uptr pc, uptr addr);
603 void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr);
604 void ReleaseStore(ThreadState *thr, uptr pc, uptr addr);
605 void AfterSleep(ThreadState *thr, uptr pc);
606 void IncrementEpoch(ThreadState *thr);
607
608 #if !SANITIZER_GO
HeapEnd()609 uptr ALWAYS_INLINE HeapEnd() {
610 return HeapMemEnd() + PrimaryAllocator::AdditionalSize();
611 }
612 #endif
613
614 void SlotAttachAndLock(ThreadState *thr) SANITIZER_ACQUIRE(thr->slot->mtx);
615 void SlotDetach(ThreadState *thr);
616 void SlotLock(ThreadState *thr) SANITIZER_ACQUIRE(thr->slot->mtx);
617 void SlotUnlock(ThreadState *thr) SANITIZER_RELEASE(thr->slot->mtx);
618 void DoReset(ThreadState *thr, uptr epoch);
619 void FlushShadowMemory();
620
621 ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags);
622 void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber);
623 void FiberSwitch(ThreadState *thr, uptr pc, ThreadState *fiber, unsigned flags);
624
625 // These need to match __tsan_switch_to_fiber_* flags defined in
626 // tsan_interface.h. See documentation there as well.
627 enum FiberSwitchFlags {
628 FiberSwitchFlagNoSync = 1 << 0, // __tsan_switch_to_fiber_no_sync
629 };
630
631 class SlotLocker {
632 public:
633 ALWAYS_INLINE
634 SlotLocker(ThreadState *thr, bool recursive = false)
thr_(thr)635 : thr_(thr), locked_(recursive ? thr->slot_locked : false) {
636 #if !SANITIZER_GO
637 // We are in trouble if we are here with in_blocking_func set.
638 // If in_blocking_func is set, all signals will be delivered synchronously,
639 // which means we can't lock slots since the signal handler will try
640 // to lock it recursively and deadlock.
641 DCHECK(!atomic_load(&thr->in_blocking_func, memory_order_relaxed));
642 #endif
643 if (!locked_)
644 SlotLock(thr_);
645 }
646
647 ALWAYS_INLINE
~SlotLocker()648 ~SlotLocker() {
649 if (!locked_)
650 SlotUnlock(thr_);
651 }
652
653 private:
654 ThreadState *thr_;
655 bool locked_;
656 };
657
658 class SlotUnlocker {
659 public:
SlotUnlocker(ThreadState * thr)660 SlotUnlocker(ThreadState *thr) : thr_(thr), locked_(thr->slot_locked) {
661 if (locked_)
662 SlotUnlock(thr_);
663 }
664
~SlotUnlocker()665 ~SlotUnlocker() {
666 if (locked_)
667 SlotLock(thr_);
668 }
669
670 private:
671 ThreadState *thr_;
672 bool locked_;
673 };
674
ProcessPendingSignals(ThreadState * thr)675 ALWAYS_INLINE void ProcessPendingSignals(ThreadState *thr) {
676 if (UNLIKELY(atomic_load_relaxed(&thr->pending_signals)))
677 ProcessPendingSignalsImpl(thr);
678 }
679
680 extern bool is_initialized;
681
682 ALWAYS_INLINE
LazyInitialize(ThreadState * thr)683 void LazyInitialize(ThreadState *thr) {
684 // If we can use .preinit_array, assume that __tsan_init
685 // called from .preinit_array initializes runtime before
686 // any instrumented code except when tsan is used as a
687 // shared library.
688 #if (!SANITIZER_CAN_USE_PREINIT_ARRAY || defined(SANITIZER_SHARED))
689 if (UNLIKELY(!is_initialized))
690 Initialize(thr);
691 #endif
692 }
693
694 void TraceResetForTesting();
695 void TraceSwitchPart(ThreadState *thr);
696 void TraceSwitchPartImpl(ThreadState *thr);
697 bool RestoreStack(EventType type, Sid sid, Epoch epoch, uptr addr, uptr size,
698 AccessType typ, Tid *ptid, VarSizeStackTrace *pstk,
699 MutexSet *pmset, uptr *ptag);
700
701 template <typename EventT>
TraceAcquire(ThreadState * thr,EventT ** ev)702 ALWAYS_INLINE WARN_UNUSED_RESULT bool TraceAcquire(ThreadState *thr,
703 EventT **ev) {
704 // TraceSwitchPart accesses shadow_stack, but it's called infrequently,
705 // so we check it here proactively.
706 DCHECK(thr->shadow_stack);
707 Event *pos = reinterpret_cast<Event *>(atomic_load_relaxed(&thr->trace_pos));
708 #if SANITIZER_DEBUG
709 // TraceSwitch acquires these mutexes,
710 // so we lock them here to detect deadlocks more reliably.
711 { Lock lock(&ctx->slot_mtx); }
712 { Lock lock(&thr->tctx->trace.mtx); }
713 TracePart *current = thr->tctx->trace.parts.Back();
714 if (current) {
715 DCHECK_GE(pos, ¤t->events[0]);
716 DCHECK_LE(pos, ¤t->events[TracePart::kSize]);
717 } else {
718 DCHECK_EQ(pos, nullptr);
719 }
720 #endif
721 // TracePart is allocated with mmap and is at least 4K aligned.
722 // So the following check is a faster way to check for part end.
723 // It may have false positives in the middle of the trace,
724 // they are filtered out in TraceSwitch.
725 if (UNLIKELY(((uptr)(pos + 1) & TracePart::kAlignment) == 0))
726 return false;
727 *ev = reinterpret_cast<EventT *>(pos);
728 return true;
729 }
730
731 template <typename EventT>
TraceRelease(ThreadState * thr,EventT * evp)732 ALWAYS_INLINE void TraceRelease(ThreadState *thr, EventT *evp) {
733 DCHECK_LE(evp + 1, &thr->tctx->trace.parts.Back()->events[TracePart::kSize]);
734 atomic_store_relaxed(&thr->trace_pos, (uptr)(evp + 1));
735 }
736
737 template <typename EventT>
TraceEvent(ThreadState * thr,EventT ev)738 void TraceEvent(ThreadState *thr, EventT ev) {
739 EventT *evp;
740 if (!TraceAcquire(thr, &evp)) {
741 TraceSwitchPart(thr);
742 UNUSED bool res = TraceAcquire(thr, &evp);
743 DCHECK(res);
744 }
745 *evp = ev;
746 TraceRelease(thr, evp);
747 }
748
749 ALWAYS_INLINE WARN_UNUSED_RESULT bool TryTraceFunc(ThreadState *thr,
750 uptr pc = 0) {
751 if (!kCollectHistory)
752 return true;
753 EventFunc *ev;
754 if (UNLIKELY(!TraceAcquire(thr, &ev)))
755 return false;
756 ev->is_access = 0;
757 ev->is_func = 1;
758 ev->pc = pc;
759 TraceRelease(thr, ev);
760 return true;
761 }
762
763 WARN_UNUSED_RESULT
764 bool TryTraceMemoryAccess(ThreadState *thr, uptr pc, uptr addr, uptr size,
765 AccessType typ);
766 WARN_UNUSED_RESULT
767 bool TryTraceMemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, uptr size,
768 AccessType typ);
769 void TraceMemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, uptr size,
770 AccessType typ);
771 void TraceFunc(ThreadState *thr, uptr pc = 0);
772 void TraceMutexLock(ThreadState *thr, EventType type, uptr pc, uptr addr,
773 StackID stk);
774 void TraceMutexUnlock(ThreadState *thr, uptr addr);
775 void TraceTime(ThreadState *thr);
776
777 void TraceRestartFuncExit(ThreadState *thr);
778 void TraceRestartFuncEntry(ThreadState *thr, uptr pc);
779
780 void GrowShadowStack(ThreadState *thr);
781
782 ALWAYS_INLINE
FuncEntry(ThreadState * thr,uptr pc)783 void FuncEntry(ThreadState *thr, uptr pc) {
784 DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.sid(), (void *)pc);
785 if (UNLIKELY(!TryTraceFunc(thr, pc)))
786 return TraceRestartFuncEntry(thr, pc);
787 DCHECK_GE(thr->shadow_stack_pos, thr->shadow_stack);
788 #if !SANITIZER_GO
789 DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
790 #else
791 if (thr->shadow_stack_pos == thr->shadow_stack_end)
792 GrowShadowStack(thr);
793 #endif
794 thr->shadow_stack_pos[0] = pc;
795 thr->shadow_stack_pos++;
796 }
797
798 ALWAYS_INLINE
FuncExit(ThreadState * thr)799 void FuncExit(ThreadState *thr) {
800 DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.sid());
801 if (UNLIKELY(!TryTraceFunc(thr, 0)))
802 return TraceRestartFuncExit(thr);
803 DCHECK_GT(thr->shadow_stack_pos, thr->shadow_stack);
804 #if !SANITIZER_GO
805 DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
806 #endif
807 thr->shadow_stack_pos--;
808 }
809
810 #if !SANITIZER_GO
811 extern void (*on_initialize)(void);
812 extern int (*on_finalize)(int);
813 #endif
814 } // namespace __tsan
815
816 #endif // TSAN_RTL_H
817