1 //=-- lsan_thread.cpp -----------------------------------------------------===// 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 LeakSanitizer. 10 // See lsan_thread.h for details. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "lsan_thread.h" 15 16 #include "sanitizer_common/sanitizer_common.h" 17 #include "sanitizer_common/sanitizer_placement_new.h" 18 #include "sanitizer_common/sanitizer_thread_registry.h" 19 #include "sanitizer_common/sanitizer_tls_get_addr.h" 20 #include "lsan_allocator.h" 21 #include "lsan_common.h" 22 23 namespace __lsan { 24 25 static ThreadRegistry *thread_registry; 26 27 static ThreadContextBase *CreateThreadContext(u32 tid) { 28 void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); 29 return new(mem) ThreadContext(tid); 30 } 31 32 static const uptr kMaxThreads = 1 << 13; 33 static const uptr kThreadQuarantineSize = 64; 34 35 void InitializeThreadRegistry() { 36 static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)]; 37 thread_registry = new(thread_registry_placeholder) 38 ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); 39 } 40 41 ThreadContext::ThreadContext(int tid) 42 : ThreadContextBase(tid), 43 stack_begin_(0), 44 stack_end_(0), 45 cache_begin_(0), 46 cache_end_(0), 47 tls_begin_(0), 48 tls_end_(0), 49 dtls_(nullptr) {} 50 51 struct OnStartedArgs { 52 uptr stack_begin, stack_end, 53 cache_begin, cache_end, 54 tls_begin, tls_end; 55 DTLS *dtls; 56 }; 57 58 void ThreadContext::OnStarted(void *arg) { 59 OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg); 60 stack_begin_ = args->stack_begin; 61 stack_end_ = args->stack_end; 62 tls_begin_ = args->tls_begin; 63 tls_end_ = args->tls_end; 64 cache_begin_ = args->cache_begin; 65 cache_end_ = args->cache_end; 66 dtls_ = args->dtls; 67 } 68 69 void ThreadContext::OnFinished() { 70 AllocatorThreadFinish(); 71 DTLS_Destroy(); 72 } 73 74 u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { 75 return thread_registry->CreateThread(user_id, detached, parent_tid, 76 /* arg */ nullptr); 77 } 78 79 void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) { 80 OnStartedArgs args; 81 uptr stack_size = 0; 82 uptr tls_size = 0; 83 GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size, 84 &args.tls_begin, &tls_size); 85 args.stack_end = args.stack_begin + stack_size; 86 args.tls_end = args.tls_begin + tls_size; 87 GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); 88 args.dtls = DTLS_Get(); 89 thread_registry->StartThread(tid, os_id, thread_type, &args); 90 } 91 92 void ThreadFinish() { 93 thread_registry->FinishThread(GetCurrentThread()); 94 SetCurrentThread(kInvalidTid); 95 } 96 97 ThreadContext *CurrentThreadContext() { 98 if (!thread_registry) return nullptr; 99 if (GetCurrentThread() == kInvalidTid) 100 return nullptr; 101 // No lock needed when getting current thread. 102 return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread()); 103 } 104 105 static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { 106 uptr uid = (uptr)arg; 107 if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { 108 return true; 109 } 110 return false; 111 } 112 113 u32 ThreadTid(uptr uid) { 114 return thread_registry->FindThread(FindThreadByUid, (void*)uid); 115 } 116 117 void ThreadJoin(u32 tid) { 118 CHECK_NE(tid, kInvalidTid); 119 thread_registry->JoinThread(tid, /* arg */nullptr); 120 } 121 122 void EnsureMainThreadIDIsCorrect() { 123 if (GetCurrentThread() == 0) 124 CurrentThreadContext()->os_id = GetTid(); 125 } 126 127 ///// Interface to the common LSan module. ///// 128 129 bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, 130 uptr *tls_begin, uptr *tls_end, uptr *cache_begin, 131 uptr *cache_end, DTLS **dtls) { 132 ThreadContext *context = static_cast<ThreadContext *>( 133 thread_registry->FindThreadContextByOsIDLocked(os_id)); 134 if (!context) return false; 135 *stack_begin = context->stack_begin(); 136 *stack_end = context->stack_end(); 137 *tls_begin = context->tls_begin(); 138 *tls_end = context->tls_end(); 139 *cache_begin = context->cache_begin(); 140 *cache_end = context->cache_end(); 141 *dtls = context->dtls(); 142 return true; 143 } 144 145 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, 146 void *arg) { 147 } 148 149 void LockThreadRegistry() { 150 thread_registry->Lock(); 151 } 152 153 void UnlockThreadRegistry() { 154 thread_registry->Unlock(); 155 } 156 157 ThreadRegistry *GetThreadRegistryLocked() { 158 thread_registry->CheckLocked(); 159 return thread_registry; 160 } 161 162 } // namespace __lsan 163