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