1*68d75effSDimitry Andric //===-- asan_thread.cpp ---------------------------------------------------===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 8*68d75effSDimitry Andric // 9*68d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 10*68d75effSDimitry Andric // 11*68d75effSDimitry Andric // Thread-related code. 12*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 13*68d75effSDimitry Andric #include "asan_allocator.h" 14*68d75effSDimitry Andric #include "asan_interceptors.h" 15*68d75effSDimitry Andric #include "asan_poisoning.h" 16*68d75effSDimitry Andric #include "asan_stack.h" 17*68d75effSDimitry Andric #include "asan_thread.h" 18*68d75effSDimitry Andric #include "asan_mapping.h" 19*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 20*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 21*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h" 22*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_tls_get_addr.h" 23*68d75effSDimitry Andric #include "lsan/lsan_common.h" 24*68d75effSDimitry Andric 25*68d75effSDimitry Andric namespace __asan { 26*68d75effSDimitry Andric 27*68d75effSDimitry Andric // AsanThreadContext implementation. 28*68d75effSDimitry Andric 29*68d75effSDimitry Andric void AsanThreadContext::OnCreated(void *arg) { 30*68d75effSDimitry Andric CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg); 31*68d75effSDimitry Andric if (args->stack) 32*68d75effSDimitry Andric stack_id = StackDepotPut(*args->stack); 33*68d75effSDimitry Andric thread = args->thread; 34*68d75effSDimitry Andric thread->set_context(this); 35*68d75effSDimitry Andric } 36*68d75effSDimitry Andric 37*68d75effSDimitry Andric void AsanThreadContext::OnFinished() { 38*68d75effSDimitry Andric // Drop the link to the AsanThread object. 39*68d75effSDimitry Andric thread = nullptr; 40*68d75effSDimitry Andric } 41*68d75effSDimitry Andric 42*68d75effSDimitry Andric // MIPS requires aligned address 43*68d75effSDimitry Andric static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)]; 44*68d75effSDimitry Andric static ThreadRegistry *asan_thread_registry; 45*68d75effSDimitry Andric 46*68d75effSDimitry Andric static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED); 47*68d75effSDimitry Andric static LowLevelAllocator allocator_for_thread_context; 48*68d75effSDimitry Andric 49*68d75effSDimitry Andric static ThreadContextBase *GetAsanThreadContext(u32 tid) { 50*68d75effSDimitry Andric BlockingMutexLock lock(&mu_for_thread_context); 51*68d75effSDimitry Andric return new(allocator_for_thread_context) AsanThreadContext(tid); 52*68d75effSDimitry Andric } 53*68d75effSDimitry Andric 54*68d75effSDimitry Andric ThreadRegistry &asanThreadRegistry() { 55*68d75effSDimitry Andric static bool initialized; 56*68d75effSDimitry Andric // Don't worry about thread_safety - this should be called when there is 57*68d75effSDimitry Andric // a single thread. 58*68d75effSDimitry Andric if (!initialized) { 59*68d75effSDimitry Andric // Never reuse ASan threads: we store pointer to AsanThreadContext 60*68d75effSDimitry Andric // in TSD and can't reliably tell when no more TSD destructors will 61*68d75effSDimitry Andric // be called. It would be wrong to reuse AsanThreadContext for another 62*68d75effSDimitry Andric // thread before all TSD destructors will be called for it. 63*68d75effSDimitry Andric asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry( 64*68d75effSDimitry Andric GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads); 65*68d75effSDimitry Andric initialized = true; 66*68d75effSDimitry Andric } 67*68d75effSDimitry Andric return *asan_thread_registry; 68*68d75effSDimitry Andric } 69*68d75effSDimitry Andric 70*68d75effSDimitry Andric AsanThreadContext *GetThreadContextByTidLocked(u32 tid) { 71*68d75effSDimitry Andric return static_cast<AsanThreadContext *>( 72*68d75effSDimitry Andric asanThreadRegistry().GetThreadLocked(tid)); 73*68d75effSDimitry Andric } 74*68d75effSDimitry Andric 75*68d75effSDimitry Andric // AsanThread implementation. 76*68d75effSDimitry Andric 77*68d75effSDimitry Andric AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg, 78*68d75effSDimitry Andric u32 parent_tid, StackTrace *stack, 79*68d75effSDimitry Andric bool detached) { 80*68d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 81*68d75effSDimitry Andric uptr size = RoundUpTo(sizeof(AsanThread), PageSize); 82*68d75effSDimitry Andric AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__); 83*68d75effSDimitry Andric thread->start_routine_ = start_routine; 84*68d75effSDimitry Andric thread->arg_ = arg; 85*68d75effSDimitry Andric AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; 86*68d75effSDimitry Andric asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached, 87*68d75effSDimitry Andric parent_tid, &args); 88*68d75effSDimitry Andric 89*68d75effSDimitry Andric return thread; 90*68d75effSDimitry Andric } 91*68d75effSDimitry Andric 92*68d75effSDimitry Andric void AsanThread::TSDDtor(void *tsd) { 93*68d75effSDimitry Andric AsanThreadContext *context = (AsanThreadContext*)tsd; 94*68d75effSDimitry Andric VReport(1, "T%d TSDDtor\n", context->tid); 95*68d75effSDimitry Andric if (context->thread) 96*68d75effSDimitry Andric context->thread->Destroy(); 97*68d75effSDimitry Andric } 98*68d75effSDimitry Andric 99*68d75effSDimitry Andric void AsanThread::Destroy() { 100*68d75effSDimitry Andric int tid = this->tid(); 101*68d75effSDimitry Andric VReport(1, "T%d exited\n", tid); 102*68d75effSDimitry Andric 103*68d75effSDimitry Andric malloc_storage().CommitBack(); 104*68d75effSDimitry Andric if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack(); 105*68d75effSDimitry Andric asanThreadRegistry().FinishThread(tid); 106*68d75effSDimitry Andric FlushToDeadThreadStats(&stats_); 107*68d75effSDimitry Andric // We also clear the shadow on thread destruction because 108*68d75effSDimitry Andric // some code may still be executing in later TSD destructors 109*68d75effSDimitry Andric // and we don't want it to have any poisoned stack. 110*68d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 111*68d75effSDimitry Andric DeleteFakeStack(tid); 112*68d75effSDimitry Andric uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached()); 113*68d75effSDimitry Andric UnmapOrDie(this, size); 114*68d75effSDimitry Andric DTLS_Destroy(); 115*68d75effSDimitry Andric } 116*68d75effSDimitry Andric 117*68d75effSDimitry Andric void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, 118*68d75effSDimitry Andric uptr size) { 119*68d75effSDimitry Andric if (atomic_load(&stack_switching_, memory_order_relaxed)) { 120*68d75effSDimitry Andric Report("ERROR: starting fiber switch while in fiber switch\n"); 121*68d75effSDimitry Andric Die(); 122*68d75effSDimitry Andric } 123*68d75effSDimitry Andric 124*68d75effSDimitry Andric next_stack_bottom_ = bottom; 125*68d75effSDimitry Andric next_stack_top_ = bottom + size; 126*68d75effSDimitry Andric atomic_store(&stack_switching_, 1, memory_order_release); 127*68d75effSDimitry Andric 128*68d75effSDimitry Andric FakeStack *current_fake_stack = fake_stack_; 129*68d75effSDimitry Andric if (fake_stack_save) 130*68d75effSDimitry Andric *fake_stack_save = fake_stack_; 131*68d75effSDimitry Andric fake_stack_ = nullptr; 132*68d75effSDimitry Andric SetTLSFakeStack(nullptr); 133*68d75effSDimitry Andric // if fake_stack_save is null, the fiber will die, delete the fakestack 134*68d75effSDimitry Andric if (!fake_stack_save && current_fake_stack) 135*68d75effSDimitry Andric current_fake_stack->Destroy(this->tid()); 136*68d75effSDimitry Andric } 137*68d75effSDimitry Andric 138*68d75effSDimitry Andric void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, 139*68d75effSDimitry Andric uptr *bottom_old, 140*68d75effSDimitry Andric uptr *size_old) { 141*68d75effSDimitry Andric if (!atomic_load(&stack_switching_, memory_order_relaxed)) { 142*68d75effSDimitry Andric Report("ERROR: finishing a fiber switch that has not started\n"); 143*68d75effSDimitry Andric Die(); 144*68d75effSDimitry Andric } 145*68d75effSDimitry Andric 146*68d75effSDimitry Andric if (fake_stack_save) { 147*68d75effSDimitry Andric SetTLSFakeStack(fake_stack_save); 148*68d75effSDimitry Andric fake_stack_ = fake_stack_save; 149*68d75effSDimitry Andric } 150*68d75effSDimitry Andric 151*68d75effSDimitry Andric if (bottom_old) 152*68d75effSDimitry Andric *bottom_old = stack_bottom_; 153*68d75effSDimitry Andric if (size_old) 154*68d75effSDimitry Andric *size_old = stack_top_ - stack_bottom_; 155*68d75effSDimitry Andric stack_bottom_ = next_stack_bottom_; 156*68d75effSDimitry Andric stack_top_ = next_stack_top_; 157*68d75effSDimitry Andric atomic_store(&stack_switching_, 0, memory_order_release); 158*68d75effSDimitry Andric next_stack_top_ = 0; 159*68d75effSDimitry Andric next_stack_bottom_ = 0; 160*68d75effSDimitry Andric } 161*68d75effSDimitry Andric 162*68d75effSDimitry Andric inline AsanThread::StackBounds AsanThread::GetStackBounds() const { 163*68d75effSDimitry Andric if (!atomic_load(&stack_switching_, memory_order_acquire)) { 164*68d75effSDimitry Andric // Make sure the stack bounds are fully initialized. 165*68d75effSDimitry Andric if (stack_bottom_ >= stack_top_) return {0, 0}; 166*68d75effSDimitry Andric return {stack_bottom_, stack_top_}; 167*68d75effSDimitry Andric } 168*68d75effSDimitry Andric char local; 169*68d75effSDimitry Andric const uptr cur_stack = (uptr)&local; 170*68d75effSDimitry Andric // Note: need to check next stack first, because FinishSwitchFiber 171*68d75effSDimitry Andric // may be in process of overwriting stack_top_/bottom_. But in such case 172*68d75effSDimitry Andric // we are already on the next stack. 173*68d75effSDimitry Andric if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_) 174*68d75effSDimitry Andric return {next_stack_bottom_, next_stack_top_}; 175*68d75effSDimitry Andric return {stack_bottom_, stack_top_}; 176*68d75effSDimitry Andric } 177*68d75effSDimitry Andric 178*68d75effSDimitry Andric uptr AsanThread::stack_top() { 179*68d75effSDimitry Andric return GetStackBounds().top; 180*68d75effSDimitry Andric } 181*68d75effSDimitry Andric 182*68d75effSDimitry Andric uptr AsanThread::stack_bottom() { 183*68d75effSDimitry Andric return GetStackBounds().bottom; 184*68d75effSDimitry Andric } 185*68d75effSDimitry Andric 186*68d75effSDimitry Andric uptr AsanThread::stack_size() { 187*68d75effSDimitry Andric const auto bounds = GetStackBounds(); 188*68d75effSDimitry Andric return bounds.top - bounds.bottom; 189*68d75effSDimitry Andric } 190*68d75effSDimitry Andric 191*68d75effSDimitry Andric // We want to create the FakeStack lazyly on the first use, but not eralier 192*68d75effSDimitry Andric // than the stack size is known and the procedure has to be async-signal safe. 193*68d75effSDimitry Andric FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { 194*68d75effSDimitry Andric uptr stack_size = this->stack_size(); 195*68d75effSDimitry Andric if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. 196*68d75effSDimitry Andric return nullptr; 197*68d75effSDimitry Andric uptr old_val = 0; 198*68d75effSDimitry Andric // fake_stack_ has 3 states: 199*68d75effSDimitry Andric // 0 -- not initialized 200*68d75effSDimitry Andric // 1 -- being initialized 201*68d75effSDimitry Andric // ptr -- initialized 202*68d75effSDimitry Andric // This CAS checks if the state was 0 and if so changes it to state 1, 203*68d75effSDimitry Andric // if that was successful, it initializes the pointer. 204*68d75effSDimitry Andric if (atomic_compare_exchange_strong( 205*68d75effSDimitry Andric reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL, 206*68d75effSDimitry Andric memory_order_relaxed)) { 207*68d75effSDimitry Andric uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size)); 208*68d75effSDimitry Andric CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log); 209*68d75effSDimitry Andric stack_size_log = 210*68d75effSDimitry Andric Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log)); 211*68d75effSDimitry Andric stack_size_log = 212*68d75effSDimitry Andric Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log)); 213*68d75effSDimitry Andric fake_stack_ = FakeStack::Create(stack_size_log); 214*68d75effSDimitry Andric SetTLSFakeStack(fake_stack_); 215*68d75effSDimitry Andric return fake_stack_; 216*68d75effSDimitry Andric } 217*68d75effSDimitry Andric return nullptr; 218*68d75effSDimitry Andric } 219*68d75effSDimitry Andric 220*68d75effSDimitry Andric void AsanThread::Init(const InitOptions *options) { 221*68d75effSDimitry Andric next_stack_top_ = next_stack_bottom_ = 0; 222*68d75effSDimitry Andric atomic_store(&stack_switching_, false, memory_order_release); 223*68d75effSDimitry Andric CHECK_EQ(this->stack_size(), 0U); 224*68d75effSDimitry Andric SetThreadStackAndTls(options); 225*68d75effSDimitry Andric if (stack_top_ != stack_bottom_) { 226*68d75effSDimitry Andric CHECK_GT(this->stack_size(), 0U); 227*68d75effSDimitry Andric CHECK(AddrIsInMem(stack_bottom_)); 228*68d75effSDimitry Andric CHECK(AddrIsInMem(stack_top_ - 1)); 229*68d75effSDimitry Andric } 230*68d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 231*68d75effSDimitry Andric fake_stack_ = nullptr; 232*68d75effSDimitry Andric if (__asan_option_detect_stack_use_after_return) 233*68d75effSDimitry Andric AsyncSignalSafeLazyInitFakeStack(); 234*68d75effSDimitry Andric int local = 0; 235*68d75effSDimitry Andric VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), 236*68d75effSDimitry Andric (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_, 237*68d75effSDimitry Andric &local); 238*68d75effSDimitry Andric } 239*68d75effSDimitry Andric 240*68d75effSDimitry Andric // Fuchsia and RTEMS don't use ThreadStart. 241*68d75effSDimitry Andric // asan_fuchsia.c/asan_rtems.c define CreateMainThread and 242*68d75effSDimitry Andric // SetThreadStackAndTls. 243*68d75effSDimitry Andric #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 244*68d75effSDimitry Andric 245*68d75effSDimitry Andric thread_return_t AsanThread::ThreadStart( 246*68d75effSDimitry Andric tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) { 247*68d75effSDimitry Andric Init(); 248*68d75effSDimitry Andric asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr); 249*68d75effSDimitry Andric if (signal_thread_is_registered) 250*68d75effSDimitry Andric atomic_store(signal_thread_is_registered, 1, memory_order_release); 251*68d75effSDimitry Andric 252*68d75effSDimitry Andric if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); 253*68d75effSDimitry Andric 254*68d75effSDimitry Andric if (!start_routine_) { 255*68d75effSDimitry Andric // start_routine_ == 0 if we're on the main thread or on one of the 256*68d75effSDimitry Andric // OS X libdispatch worker threads. But nobody is supposed to call 257*68d75effSDimitry Andric // ThreadStart() for the worker threads. 258*68d75effSDimitry Andric CHECK_EQ(tid(), 0); 259*68d75effSDimitry Andric return 0; 260*68d75effSDimitry Andric } 261*68d75effSDimitry Andric 262*68d75effSDimitry Andric thread_return_t res = start_routine_(arg_); 263*68d75effSDimitry Andric 264*68d75effSDimitry Andric // On POSIX systems we defer this to the TSD destructor. LSan will consider 265*68d75effSDimitry Andric // the thread's memory as non-live from the moment we call Destroy(), even 266*68d75effSDimitry Andric // though that memory might contain pointers to heap objects which will be 267*68d75effSDimitry Andric // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before 268*68d75effSDimitry Andric // the TSD destructors have run might cause false positives in LSan. 269*68d75effSDimitry Andric if (!SANITIZER_POSIX) 270*68d75effSDimitry Andric this->Destroy(); 271*68d75effSDimitry Andric 272*68d75effSDimitry Andric return res; 273*68d75effSDimitry Andric } 274*68d75effSDimitry Andric 275*68d75effSDimitry Andric AsanThread *CreateMainThread() { 276*68d75effSDimitry Andric AsanThread *main_thread = AsanThread::Create( 277*68d75effSDimitry Andric /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0, 278*68d75effSDimitry Andric /* stack */ nullptr, /* detached */ true); 279*68d75effSDimitry Andric SetCurrentThread(main_thread); 280*68d75effSDimitry Andric main_thread->ThreadStart(internal_getpid(), 281*68d75effSDimitry Andric /* signal_thread_is_registered */ nullptr); 282*68d75effSDimitry Andric return main_thread; 283*68d75effSDimitry Andric } 284*68d75effSDimitry Andric 285*68d75effSDimitry Andric // This implementation doesn't use the argument, which is just passed down 286*68d75effSDimitry Andric // from the caller of Init (which see, above). It's only there to support 287*68d75effSDimitry Andric // OS-specific implementations that need more information passed through. 288*68d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const InitOptions *options) { 289*68d75effSDimitry Andric DCHECK_EQ(options, nullptr); 290*68d75effSDimitry Andric uptr tls_size = 0; 291*68d75effSDimitry Andric uptr stack_size = 0; 292*68d75effSDimitry Andric GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_, 293*68d75effSDimitry Andric &tls_size); 294*68d75effSDimitry Andric stack_top_ = stack_bottom_ + stack_size; 295*68d75effSDimitry Andric tls_end_ = tls_begin_ + tls_size; 296*68d75effSDimitry Andric dtls_ = DTLS_Get(); 297*68d75effSDimitry Andric 298*68d75effSDimitry Andric if (stack_top_ != stack_bottom_) { 299*68d75effSDimitry Andric int local; 300*68d75effSDimitry Andric CHECK(AddrIsInStack((uptr)&local)); 301*68d75effSDimitry Andric } 302*68d75effSDimitry Andric } 303*68d75effSDimitry Andric 304*68d75effSDimitry Andric #endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 305*68d75effSDimitry Andric 306*68d75effSDimitry Andric void AsanThread::ClearShadowForThreadStackAndTLS() { 307*68d75effSDimitry Andric if (stack_top_ != stack_bottom_) 308*68d75effSDimitry Andric PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); 309*68d75effSDimitry Andric if (tls_begin_ != tls_end_) { 310*68d75effSDimitry Andric uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY); 311*68d75effSDimitry Andric uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY); 312*68d75effSDimitry Andric FastPoisonShadowPartialRightRedzone(tls_begin_aligned, 313*68d75effSDimitry Andric tls_end_ - tls_begin_aligned, 314*68d75effSDimitry Andric tls_end_aligned - tls_end_, 0); 315*68d75effSDimitry Andric } 316*68d75effSDimitry Andric } 317*68d75effSDimitry Andric 318*68d75effSDimitry Andric bool AsanThread::GetStackFrameAccessByAddr(uptr addr, 319*68d75effSDimitry Andric StackFrameAccess *access) { 320*68d75effSDimitry Andric if (stack_top_ == stack_bottom_) 321*68d75effSDimitry Andric return false; 322*68d75effSDimitry Andric 323*68d75effSDimitry Andric uptr bottom = 0; 324*68d75effSDimitry Andric if (AddrIsInStack(addr)) { 325*68d75effSDimitry Andric bottom = stack_bottom(); 326*68d75effSDimitry Andric } else if (has_fake_stack()) { 327*68d75effSDimitry Andric bottom = fake_stack()->AddrIsInFakeStack(addr); 328*68d75effSDimitry Andric CHECK(bottom); 329*68d75effSDimitry Andric access->offset = addr - bottom; 330*68d75effSDimitry Andric access->frame_pc = ((uptr*)bottom)[2]; 331*68d75effSDimitry Andric access->frame_descr = (const char *)((uptr*)bottom)[1]; 332*68d75effSDimitry Andric return true; 333*68d75effSDimitry Andric } 334*68d75effSDimitry Andric uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr. 335*68d75effSDimitry Andric uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY); 336*68d75effSDimitry Andric u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); 337*68d75effSDimitry Andric u8 *shadow_bottom = (u8*)MemToShadow(bottom); 338*68d75effSDimitry Andric 339*68d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 340*68d75effSDimitry Andric *shadow_ptr != kAsanStackLeftRedzoneMagic) { 341*68d75effSDimitry Andric shadow_ptr--; 342*68d75effSDimitry Andric mem_ptr -= SHADOW_GRANULARITY; 343*68d75effSDimitry Andric } 344*68d75effSDimitry Andric 345*68d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 346*68d75effSDimitry Andric *shadow_ptr == kAsanStackLeftRedzoneMagic) { 347*68d75effSDimitry Andric shadow_ptr--; 348*68d75effSDimitry Andric mem_ptr -= SHADOW_GRANULARITY; 349*68d75effSDimitry Andric } 350*68d75effSDimitry Andric 351*68d75effSDimitry Andric if (shadow_ptr < shadow_bottom) { 352*68d75effSDimitry Andric return false; 353*68d75effSDimitry Andric } 354*68d75effSDimitry Andric 355*68d75effSDimitry Andric uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY); 356*68d75effSDimitry Andric CHECK(ptr[0] == kCurrentStackFrameMagic); 357*68d75effSDimitry Andric access->offset = addr - (uptr)ptr; 358*68d75effSDimitry Andric access->frame_pc = ptr[2]; 359*68d75effSDimitry Andric access->frame_descr = (const char*)ptr[1]; 360*68d75effSDimitry Andric return true; 361*68d75effSDimitry Andric } 362*68d75effSDimitry Andric 363*68d75effSDimitry Andric uptr AsanThread::GetStackVariableShadowStart(uptr addr) { 364*68d75effSDimitry Andric uptr bottom = 0; 365*68d75effSDimitry Andric if (AddrIsInStack(addr)) { 366*68d75effSDimitry Andric bottom = stack_bottom(); 367*68d75effSDimitry Andric } else if (has_fake_stack()) { 368*68d75effSDimitry Andric bottom = fake_stack()->AddrIsInFakeStack(addr); 369*68d75effSDimitry Andric CHECK(bottom); 370*68d75effSDimitry Andric } else { 371*68d75effSDimitry Andric return 0; 372*68d75effSDimitry Andric } 373*68d75effSDimitry Andric 374*68d75effSDimitry Andric uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr. 375*68d75effSDimitry Andric u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); 376*68d75effSDimitry Andric u8 *shadow_bottom = (u8*)MemToShadow(bottom); 377*68d75effSDimitry Andric 378*68d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 379*68d75effSDimitry Andric (*shadow_ptr != kAsanStackLeftRedzoneMagic && 380*68d75effSDimitry Andric *shadow_ptr != kAsanStackMidRedzoneMagic && 381*68d75effSDimitry Andric *shadow_ptr != kAsanStackRightRedzoneMagic)) 382*68d75effSDimitry Andric shadow_ptr--; 383*68d75effSDimitry Andric 384*68d75effSDimitry Andric return (uptr)shadow_ptr + 1; 385*68d75effSDimitry Andric } 386*68d75effSDimitry Andric 387*68d75effSDimitry Andric bool AsanThread::AddrIsInStack(uptr addr) { 388*68d75effSDimitry Andric const auto bounds = GetStackBounds(); 389*68d75effSDimitry Andric return addr >= bounds.bottom && addr < bounds.top; 390*68d75effSDimitry Andric } 391*68d75effSDimitry Andric 392*68d75effSDimitry Andric static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, 393*68d75effSDimitry Andric void *addr) { 394*68d75effSDimitry Andric AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base); 395*68d75effSDimitry Andric AsanThread *t = tctx->thread; 396*68d75effSDimitry Andric if (!t) return false; 397*68d75effSDimitry Andric if (t->AddrIsInStack((uptr)addr)) return true; 398*68d75effSDimitry Andric if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr)) 399*68d75effSDimitry Andric return true; 400*68d75effSDimitry Andric return false; 401*68d75effSDimitry Andric } 402*68d75effSDimitry Andric 403*68d75effSDimitry Andric AsanThread *GetCurrentThread() { 404*68d75effSDimitry Andric if (SANITIZER_RTEMS && !asan_inited) 405*68d75effSDimitry Andric return nullptr; 406*68d75effSDimitry Andric 407*68d75effSDimitry Andric AsanThreadContext *context = 408*68d75effSDimitry Andric reinterpret_cast<AsanThreadContext *>(AsanTSDGet()); 409*68d75effSDimitry Andric if (!context) { 410*68d75effSDimitry Andric if (SANITIZER_ANDROID) { 411*68d75effSDimitry Andric // On Android, libc constructor is called _after_ asan_init, and cleans up 412*68d75effSDimitry Andric // TSD. Try to figure out if this is still the main thread by the stack 413*68d75effSDimitry Andric // address. We are not entirely sure that we have correct main thread 414*68d75effSDimitry Andric // limits, so only do this magic on Android, and only if the found thread 415*68d75effSDimitry Andric // is the main thread. 416*68d75effSDimitry Andric AsanThreadContext *tctx = GetThreadContextByTidLocked(0); 417*68d75effSDimitry Andric if (tctx && ThreadStackContainsAddress(tctx, &context)) { 418*68d75effSDimitry Andric SetCurrentThread(tctx->thread); 419*68d75effSDimitry Andric return tctx->thread; 420*68d75effSDimitry Andric } 421*68d75effSDimitry Andric } 422*68d75effSDimitry Andric return nullptr; 423*68d75effSDimitry Andric } 424*68d75effSDimitry Andric return context->thread; 425*68d75effSDimitry Andric } 426*68d75effSDimitry Andric 427*68d75effSDimitry Andric void SetCurrentThread(AsanThread *t) { 428*68d75effSDimitry Andric CHECK(t->context()); 429*68d75effSDimitry Andric VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(), 430*68d75effSDimitry Andric (void *)GetThreadSelf()); 431*68d75effSDimitry Andric // Make sure we do not reset the current AsanThread. 432*68d75effSDimitry Andric CHECK_EQ(0, AsanTSDGet()); 433*68d75effSDimitry Andric AsanTSDSet(t->context()); 434*68d75effSDimitry Andric CHECK_EQ(t->context(), AsanTSDGet()); 435*68d75effSDimitry Andric } 436*68d75effSDimitry Andric 437*68d75effSDimitry Andric u32 GetCurrentTidOrInvalid() { 438*68d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 439*68d75effSDimitry Andric return t ? t->tid() : kInvalidTid; 440*68d75effSDimitry Andric } 441*68d75effSDimitry Andric 442*68d75effSDimitry Andric AsanThread *FindThreadByStackAddress(uptr addr) { 443*68d75effSDimitry Andric asanThreadRegistry().CheckLocked(); 444*68d75effSDimitry Andric AsanThreadContext *tctx = static_cast<AsanThreadContext *>( 445*68d75effSDimitry Andric asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress, 446*68d75effSDimitry Andric (void *)addr)); 447*68d75effSDimitry Andric return tctx ? tctx->thread : nullptr; 448*68d75effSDimitry Andric } 449*68d75effSDimitry Andric 450*68d75effSDimitry Andric void EnsureMainThreadIDIsCorrect() { 451*68d75effSDimitry Andric AsanThreadContext *context = 452*68d75effSDimitry Andric reinterpret_cast<AsanThreadContext *>(AsanTSDGet()); 453*68d75effSDimitry Andric if (context && (context->tid == 0)) 454*68d75effSDimitry Andric context->os_id = GetTid(); 455*68d75effSDimitry Andric } 456*68d75effSDimitry Andric 457*68d75effSDimitry Andric __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) { 458*68d75effSDimitry Andric __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( 459*68d75effSDimitry Andric __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); 460*68d75effSDimitry Andric if (!context) return nullptr; 461*68d75effSDimitry Andric return context->thread; 462*68d75effSDimitry Andric } 463*68d75effSDimitry Andric } // namespace __asan 464*68d75effSDimitry Andric 465*68d75effSDimitry Andric // --- Implementation of LSan-specific functions --- {{{1 466*68d75effSDimitry Andric namespace __lsan { 467*68d75effSDimitry Andric bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, 468*68d75effSDimitry Andric uptr *tls_begin, uptr *tls_end, uptr *cache_begin, 469*68d75effSDimitry Andric uptr *cache_end, DTLS **dtls) { 470*68d75effSDimitry Andric __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); 471*68d75effSDimitry Andric if (!t) return false; 472*68d75effSDimitry Andric *stack_begin = t->stack_bottom(); 473*68d75effSDimitry Andric *stack_end = t->stack_top(); 474*68d75effSDimitry Andric *tls_begin = t->tls_begin(); 475*68d75effSDimitry Andric *tls_end = t->tls_end(); 476*68d75effSDimitry Andric // ASan doesn't keep allocator caches in TLS, so these are unused. 477*68d75effSDimitry Andric *cache_begin = 0; 478*68d75effSDimitry Andric *cache_end = 0; 479*68d75effSDimitry Andric *dtls = t->dtls(); 480*68d75effSDimitry Andric return true; 481*68d75effSDimitry Andric } 482*68d75effSDimitry Andric 483*68d75effSDimitry Andric void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, 484*68d75effSDimitry Andric void *arg) { 485*68d75effSDimitry Andric __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); 486*68d75effSDimitry Andric if (t && t->has_fake_stack()) 487*68d75effSDimitry Andric t->fake_stack()->ForEachFakeFrame(callback, arg); 488*68d75effSDimitry Andric } 489*68d75effSDimitry Andric 490*68d75effSDimitry Andric void LockThreadRegistry() { 491*68d75effSDimitry Andric __asan::asanThreadRegistry().Lock(); 492*68d75effSDimitry Andric } 493*68d75effSDimitry Andric 494*68d75effSDimitry Andric void UnlockThreadRegistry() { 495*68d75effSDimitry Andric __asan::asanThreadRegistry().Unlock(); 496*68d75effSDimitry Andric } 497*68d75effSDimitry Andric 498*68d75effSDimitry Andric ThreadRegistry *GetThreadRegistryLocked() { 499*68d75effSDimitry Andric __asan::asanThreadRegistry().CheckLocked(); 500*68d75effSDimitry Andric return &__asan::asanThreadRegistry(); 501*68d75effSDimitry Andric } 502*68d75effSDimitry Andric 503*68d75effSDimitry Andric void EnsureMainThreadIDIsCorrect() { 504*68d75effSDimitry Andric __asan::EnsureMainThreadIDIsCorrect(); 505*68d75effSDimitry Andric } 506*68d75effSDimitry Andric } // namespace __lsan 507*68d75effSDimitry Andric 508*68d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1 509*68d75effSDimitry Andric using namespace __asan; 510*68d75effSDimitry Andric 511*68d75effSDimitry Andric extern "C" { 512*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 513*68d75effSDimitry Andric void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom, 514*68d75effSDimitry Andric uptr size) { 515*68d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 516*68d75effSDimitry Andric if (!t) { 517*68d75effSDimitry Andric VReport(1, "__asan_start_switch_fiber called from unknown thread\n"); 518*68d75effSDimitry Andric return; 519*68d75effSDimitry Andric } 520*68d75effSDimitry Andric t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size); 521*68d75effSDimitry Andric } 522*68d75effSDimitry Andric 523*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 524*68d75effSDimitry Andric void __sanitizer_finish_switch_fiber(void* fakestack, 525*68d75effSDimitry Andric const void **bottom_old, 526*68d75effSDimitry Andric uptr *size_old) { 527*68d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 528*68d75effSDimitry Andric if (!t) { 529*68d75effSDimitry Andric VReport(1, "__asan_finish_switch_fiber called from unknown thread\n"); 530*68d75effSDimitry Andric return; 531*68d75effSDimitry Andric } 532*68d75effSDimitry Andric t->FinishSwitchFiber((FakeStack*)fakestack, 533*68d75effSDimitry Andric (uptr*)bottom_old, 534*68d75effSDimitry Andric (uptr*)size_old); 535*68d75effSDimitry Andric } 536*68d75effSDimitry Andric } 537