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