168d75effSDimitry Andric //===-- asan_thread.cpp ---------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Thread-related code. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric #include "asan_allocator.h" 1468d75effSDimitry Andric #include "asan_interceptors.h" 1568d75effSDimitry Andric #include "asan_poisoning.h" 1668d75effSDimitry Andric #include "asan_stack.h" 1768d75effSDimitry Andric #include "asan_thread.h" 1868d75effSDimitry Andric #include "asan_mapping.h" 1968d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 2068d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h" 2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_tls_get_addr.h" 2368d75effSDimitry Andric #include "lsan/lsan_common.h" 2468d75effSDimitry Andric 2568d75effSDimitry Andric namespace __asan { 2668d75effSDimitry Andric 2768d75effSDimitry Andric // AsanThreadContext implementation. 2868d75effSDimitry Andric 2968d75effSDimitry Andric void AsanThreadContext::OnCreated(void *arg) { 3068d75effSDimitry Andric CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg); 3168d75effSDimitry Andric if (args->stack) 3268d75effSDimitry Andric stack_id = StackDepotPut(*args->stack); 3368d75effSDimitry Andric thread = args->thread; 3468d75effSDimitry Andric thread->set_context(this); 3568d75effSDimitry Andric } 3668d75effSDimitry Andric 3768d75effSDimitry Andric void AsanThreadContext::OnFinished() { 3868d75effSDimitry Andric // Drop the link to the AsanThread object. 3968d75effSDimitry Andric thread = nullptr; 4068d75effSDimitry Andric } 4168d75effSDimitry Andric 4268d75effSDimitry Andric // MIPS requires aligned address 4368d75effSDimitry Andric static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)]; 4468d75effSDimitry Andric static ThreadRegistry *asan_thread_registry; 4568d75effSDimitry Andric 4668d75effSDimitry Andric static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED); 4768d75effSDimitry Andric static LowLevelAllocator allocator_for_thread_context; 4868d75effSDimitry Andric 4968d75effSDimitry Andric static ThreadContextBase *GetAsanThreadContext(u32 tid) { 5068d75effSDimitry Andric BlockingMutexLock lock(&mu_for_thread_context); 5168d75effSDimitry Andric return new(allocator_for_thread_context) AsanThreadContext(tid); 5268d75effSDimitry Andric } 5368d75effSDimitry Andric 5468d75effSDimitry Andric ThreadRegistry &asanThreadRegistry() { 5568d75effSDimitry Andric static bool initialized; 5668d75effSDimitry Andric // Don't worry about thread_safety - this should be called when there is 5768d75effSDimitry Andric // a single thread. 5868d75effSDimitry Andric if (!initialized) { 5968d75effSDimitry Andric // Never reuse ASan threads: we store pointer to AsanThreadContext 6068d75effSDimitry Andric // in TSD and can't reliably tell when no more TSD destructors will 6168d75effSDimitry Andric // be called. It would be wrong to reuse AsanThreadContext for another 6268d75effSDimitry Andric // thread before all TSD destructors will be called for it. 6368d75effSDimitry Andric asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry( 6468d75effSDimitry Andric GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads); 6568d75effSDimitry Andric initialized = true; 6668d75effSDimitry Andric } 6768d75effSDimitry Andric return *asan_thread_registry; 6868d75effSDimitry Andric } 6968d75effSDimitry Andric 7068d75effSDimitry Andric AsanThreadContext *GetThreadContextByTidLocked(u32 tid) { 7168d75effSDimitry Andric return static_cast<AsanThreadContext *>( 7268d75effSDimitry Andric asanThreadRegistry().GetThreadLocked(tid)); 7368d75effSDimitry Andric } 7468d75effSDimitry Andric 7568d75effSDimitry Andric // AsanThread implementation. 7668d75effSDimitry Andric 7768d75effSDimitry Andric AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg, 7868d75effSDimitry Andric u32 parent_tid, StackTrace *stack, 7968d75effSDimitry Andric bool detached) { 8068d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 8168d75effSDimitry Andric uptr size = RoundUpTo(sizeof(AsanThread), PageSize); 8268d75effSDimitry Andric AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__); 8368d75effSDimitry Andric thread->start_routine_ = start_routine; 8468d75effSDimitry Andric thread->arg_ = arg; 8568d75effSDimitry Andric AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; 8668d75effSDimitry Andric asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached, 8768d75effSDimitry Andric parent_tid, &args); 8868d75effSDimitry Andric 8968d75effSDimitry Andric return thread; 9068d75effSDimitry Andric } 9168d75effSDimitry Andric 9268d75effSDimitry Andric void AsanThread::TSDDtor(void *tsd) { 9368d75effSDimitry Andric AsanThreadContext *context = (AsanThreadContext*)tsd; 9468d75effSDimitry Andric VReport(1, "T%d TSDDtor\n", context->tid); 9568d75effSDimitry Andric if (context->thread) 9668d75effSDimitry Andric context->thread->Destroy(); 9768d75effSDimitry Andric } 9868d75effSDimitry Andric 9968d75effSDimitry Andric void AsanThread::Destroy() { 10068d75effSDimitry Andric int tid = this->tid(); 10168d75effSDimitry Andric VReport(1, "T%d exited\n", tid); 10268d75effSDimitry Andric 10368d75effSDimitry Andric malloc_storage().CommitBack(); 10468d75effSDimitry Andric if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack(); 10568d75effSDimitry Andric asanThreadRegistry().FinishThread(tid); 10668d75effSDimitry Andric FlushToDeadThreadStats(&stats_); 10768d75effSDimitry Andric // We also clear the shadow on thread destruction because 10868d75effSDimitry Andric // some code may still be executing in later TSD destructors 10968d75effSDimitry Andric // and we don't want it to have any poisoned stack. 11068d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 11168d75effSDimitry Andric DeleteFakeStack(tid); 11268d75effSDimitry Andric uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached()); 11368d75effSDimitry Andric UnmapOrDie(this, size); 11468d75effSDimitry Andric DTLS_Destroy(); 11568d75effSDimitry Andric } 11668d75effSDimitry Andric 11768d75effSDimitry Andric void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, 11868d75effSDimitry Andric uptr size) { 11968d75effSDimitry Andric if (atomic_load(&stack_switching_, memory_order_relaxed)) { 12068d75effSDimitry Andric Report("ERROR: starting fiber switch while in fiber switch\n"); 12168d75effSDimitry Andric Die(); 12268d75effSDimitry Andric } 12368d75effSDimitry Andric 12468d75effSDimitry Andric next_stack_bottom_ = bottom; 12568d75effSDimitry Andric next_stack_top_ = bottom + size; 12668d75effSDimitry Andric atomic_store(&stack_switching_, 1, memory_order_release); 12768d75effSDimitry Andric 12868d75effSDimitry Andric FakeStack *current_fake_stack = fake_stack_; 12968d75effSDimitry Andric if (fake_stack_save) 13068d75effSDimitry Andric *fake_stack_save = fake_stack_; 13168d75effSDimitry Andric fake_stack_ = nullptr; 13268d75effSDimitry Andric SetTLSFakeStack(nullptr); 13368d75effSDimitry Andric // if fake_stack_save is null, the fiber will die, delete the fakestack 13468d75effSDimitry Andric if (!fake_stack_save && current_fake_stack) 13568d75effSDimitry Andric current_fake_stack->Destroy(this->tid()); 13668d75effSDimitry Andric } 13768d75effSDimitry Andric 13868d75effSDimitry Andric void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, 13968d75effSDimitry Andric uptr *bottom_old, 14068d75effSDimitry Andric uptr *size_old) { 14168d75effSDimitry Andric if (!atomic_load(&stack_switching_, memory_order_relaxed)) { 14268d75effSDimitry Andric Report("ERROR: finishing a fiber switch that has not started\n"); 14368d75effSDimitry Andric Die(); 14468d75effSDimitry Andric } 14568d75effSDimitry Andric 14668d75effSDimitry Andric if (fake_stack_save) { 14768d75effSDimitry Andric SetTLSFakeStack(fake_stack_save); 14868d75effSDimitry Andric fake_stack_ = fake_stack_save; 14968d75effSDimitry Andric } 15068d75effSDimitry Andric 15168d75effSDimitry Andric if (bottom_old) 15268d75effSDimitry Andric *bottom_old = stack_bottom_; 15368d75effSDimitry Andric if (size_old) 15468d75effSDimitry Andric *size_old = stack_top_ - stack_bottom_; 15568d75effSDimitry Andric stack_bottom_ = next_stack_bottom_; 15668d75effSDimitry Andric stack_top_ = next_stack_top_; 15768d75effSDimitry Andric atomic_store(&stack_switching_, 0, memory_order_release); 15868d75effSDimitry Andric next_stack_top_ = 0; 15968d75effSDimitry Andric next_stack_bottom_ = 0; 16068d75effSDimitry Andric } 16168d75effSDimitry Andric 16268d75effSDimitry Andric inline AsanThread::StackBounds AsanThread::GetStackBounds() const { 16368d75effSDimitry Andric if (!atomic_load(&stack_switching_, memory_order_acquire)) { 16468d75effSDimitry Andric // Make sure the stack bounds are fully initialized. 16568d75effSDimitry Andric if (stack_bottom_ >= stack_top_) return {0, 0}; 16668d75effSDimitry Andric return {stack_bottom_, stack_top_}; 16768d75effSDimitry Andric } 16868d75effSDimitry Andric char local; 16968d75effSDimitry Andric const uptr cur_stack = (uptr)&local; 17068d75effSDimitry Andric // Note: need to check next stack first, because FinishSwitchFiber 17168d75effSDimitry Andric // may be in process of overwriting stack_top_/bottom_. But in such case 17268d75effSDimitry Andric // we are already on the next stack. 17368d75effSDimitry Andric if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_) 17468d75effSDimitry Andric return {next_stack_bottom_, next_stack_top_}; 17568d75effSDimitry Andric return {stack_bottom_, stack_top_}; 17668d75effSDimitry Andric } 17768d75effSDimitry Andric 17868d75effSDimitry Andric uptr AsanThread::stack_top() { 17968d75effSDimitry Andric return GetStackBounds().top; 18068d75effSDimitry Andric } 18168d75effSDimitry Andric 18268d75effSDimitry Andric uptr AsanThread::stack_bottom() { 18368d75effSDimitry Andric return GetStackBounds().bottom; 18468d75effSDimitry Andric } 18568d75effSDimitry Andric 18668d75effSDimitry Andric uptr AsanThread::stack_size() { 18768d75effSDimitry Andric const auto bounds = GetStackBounds(); 18868d75effSDimitry Andric return bounds.top - bounds.bottom; 18968d75effSDimitry Andric } 19068d75effSDimitry Andric 191*e8d8bef9SDimitry Andric // We want to create the FakeStack lazily on the first use, but not earlier 19268d75effSDimitry Andric // than the stack size is known and the procedure has to be async-signal safe. 19368d75effSDimitry Andric FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { 19468d75effSDimitry Andric uptr stack_size = this->stack_size(); 19568d75effSDimitry Andric if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. 19668d75effSDimitry Andric return nullptr; 19768d75effSDimitry Andric uptr old_val = 0; 19868d75effSDimitry Andric // fake_stack_ has 3 states: 19968d75effSDimitry Andric // 0 -- not initialized 20068d75effSDimitry Andric // 1 -- being initialized 20168d75effSDimitry Andric // ptr -- initialized 20268d75effSDimitry Andric // This CAS checks if the state was 0 and if so changes it to state 1, 20368d75effSDimitry Andric // if that was successful, it initializes the pointer. 20468d75effSDimitry Andric if (atomic_compare_exchange_strong( 20568d75effSDimitry Andric reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL, 20668d75effSDimitry Andric memory_order_relaxed)) { 20768d75effSDimitry Andric uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size)); 20868d75effSDimitry Andric CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log); 20968d75effSDimitry Andric stack_size_log = 21068d75effSDimitry Andric Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log)); 21168d75effSDimitry Andric stack_size_log = 21268d75effSDimitry Andric Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log)); 21368d75effSDimitry Andric fake_stack_ = FakeStack::Create(stack_size_log); 214*e8d8bef9SDimitry Andric DCHECK_EQ(GetCurrentThread(), this); 21568d75effSDimitry Andric SetTLSFakeStack(fake_stack_); 21668d75effSDimitry Andric return fake_stack_; 21768d75effSDimitry Andric } 21868d75effSDimitry Andric return nullptr; 21968d75effSDimitry Andric } 22068d75effSDimitry Andric 22168d75effSDimitry Andric void AsanThread::Init(const InitOptions *options) { 222*e8d8bef9SDimitry Andric DCHECK_NE(tid(), ThreadRegistry::kUnknownTid); 22368d75effSDimitry Andric next_stack_top_ = next_stack_bottom_ = 0; 22468d75effSDimitry Andric atomic_store(&stack_switching_, false, memory_order_release); 22568d75effSDimitry Andric CHECK_EQ(this->stack_size(), 0U); 22668d75effSDimitry Andric SetThreadStackAndTls(options); 22768d75effSDimitry Andric if (stack_top_ != stack_bottom_) { 22868d75effSDimitry Andric CHECK_GT(this->stack_size(), 0U); 22968d75effSDimitry Andric CHECK(AddrIsInMem(stack_bottom_)); 23068d75effSDimitry Andric CHECK(AddrIsInMem(stack_top_ - 1)); 23168d75effSDimitry Andric } 23268d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 23368d75effSDimitry Andric fake_stack_ = nullptr; 234*e8d8bef9SDimitry Andric if (__asan_option_detect_stack_use_after_return && 235*e8d8bef9SDimitry Andric tid() == GetCurrentTidOrInvalid()) { 236*e8d8bef9SDimitry Andric // AsyncSignalSafeLazyInitFakeStack makes use of threadlocals and must be 237*e8d8bef9SDimitry Andric // called from the context of the thread it is initializing, not its parent. 238*e8d8bef9SDimitry Andric // Most platforms call AsanThread::Init on the newly-spawned thread, but 239*e8d8bef9SDimitry Andric // Fuchsia calls this function from the parent thread. To support that 240*e8d8bef9SDimitry Andric // approach, we avoid calling AsyncSignalSafeLazyInitFakeStack here; it will 241*e8d8bef9SDimitry Andric // be called by the new thread when it first attempts to access the fake 242*e8d8bef9SDimitry Andric // stack. 24368d75effSDimitry Andric AsyncSignalSafeLazyInitFakeStack(); 244*e8d8bef9SDimitry Andric } 24568d75effSDimitry Andric int local = 0; 24668d75effSDimitry Andric VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), 24768d75effSDimitry Andric (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_, 24868d75effSDimitry Andric &local); 24968d75effSDimitry Andric } 25068d75effSDimitry Andric 25168d75effSDimitry Andric // Fuchsia and RTEMS don't use ThreadStart. 25268d75effSDimitry Andric // asan_fuchsia.c/asan_rtems.c define CreateMainThread and 25368d75effSDimitry Andric // SetThreadStackAndTls. 25468d75effSDimitry Andric #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 25568d75effSDimitry Andric 256*e8d8bef9SDimitry Andric thread_return_t AsanThread::ThreadStart(tid_t os_id) { 25768d75effSDimitry Andric Init(); 25868d75effSDimitry Andric asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr); 25968d75effSDimitry Andric 26068d75effSDimitry Andric if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); 26168d75effSDimitry Andric 26268d75effSDimitry Andric if (!start_routine_) { 26368d75effSDimitry Andric // start_routine_ == 0 if we're on the main thread or on one of the 26468d75effSDimitry Andric // OS X libdispatch worker threads. But nobody is supposed to call 26568d75effSDimitry Andric // ThreadStart() for the worker threads. 26668d75effSDimitry Andric CHECK_EQ(tid(), 0); 26768d75effSDimitry Andric return 0; 26868d75effSDimitry Andric } 26968d75effSDimitry Andric 27068d75effSDimitry Andric thread_return_t res = start_routine_(arg_); 27168d75effSDimitry Andric 27268d75effSDimitry Andric // On POSIX systems we defer this to the TSD destructor. LSan will consider 27368d75effSDimitry Andric // the thread's memory as non-live from the moment we call Destroy(), even 27468d75effSDimitry Andric // though that memory might contain pointers to heap objects which will be 27568d75effSDimitry Andric // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before 27668d75effSDimitry Andric // the TSD destructors have run might cause false positives in LSan. 27768d75effSDimitry Andric if (!SANITIZER_POSIX) 27868d75effSDimitry Andric this->Destroy(); 27968d75effSDimitry Andric 28068d75effSDimitry Andric return res; 28168d75effSDimitry Andric } 28268d75effSDimitry Andric 28368d75effSDimitry Andric AsanThread *CreateMainThread() { 28468d75effSDimitry Andric AsanThread *main_thread = AsanThread::Create( 28568d75effSDimitry Andric /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0, 28668d75effSDimitry Andric /* stack */ nullptr, /* detached */ true); 28768d75effSDimitry Andric SetCurrentThread(main_thread); 288*e8d8bef9SDimitry Andric main_thread->ThreadStart(internal_getpid()); 28968d75effSDimitry Andric return main_thread; 29068d75effSDimitry Andric } 29168d75effSDimitry Andric 29268d75effSDimitry Andric // This implementation doesn't use the argument, which is just passed down 29368d75effSDimitry Andric // from the caller of Init (which see, above). It's only there to support 29468d75effSDimitry Andric // OS-specific implementations that need more information passed through. 29568d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const InitOptions *options) { 29668d75effSDimitry Andric DCHECK_EQ(options, nullptr); 29768d75effSDimitry Andric uptr tls_size = 0; 29868d75effSDimitry Andric uptr stack_size = 0; 29968d75effSDimitry Andric GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_, 30068d75effSDimitry Andric &tls_size); 30168d75effSDimitry Andric stack_top_ = stack_bottom_ + stack_size; 30268d75effSDimitry Andric tls_end_ = tls_begin_ + tls_size; 30368d75effSDimitry Andric dtls_ = DTLS_Get(); 30468d75effSDimitry Andric 30568d75effSDimitry Andric if (stack_top_ != stack_bottom_) { 30668d75effSDimitry Andric int local; 30768d75effSDimitry Andric CHECK(AddrIsInStack((uptr)&local)); 30868d75effSDimitry Andric } 30968d75effSDimitry Andric } 31068d75effSDimitry Andric 31168d75effSDimitry Andric #endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS 31268d75effSDimitry Andric 31368d75effSDimitry Andric void AsanThread::ClearShadowForThreadStackAndTLS() { 31468d75effSDimitry Andric if (stack_top_ != stack_bottom_) 31568d75effSDimitry Andric PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); 31668d75effSDimitry Andric if (tls_begin_ != tls_end_) { 31768d75effSDimitry Andric uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY); 31868d75effSDimitry Andric uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY); 31968d75effSDimitry Andric FastPoisonShadowPartialRightRedzone(tls_begin_aligned, 32068d75effSDimitry Andric tls_end_ - tls_begin_aligned, 32168d75effSDimitry Andric tls_end_aligned - tls_end_, 0); 32268d75effSDimitry Andric } 32368d75effSDimitry Andric } 32468d75effSDimitry Andric 32568d75effSDimitry Andric bool AsanThread::GetStackFrameAccessByAddr(uptr addr, 32668d75effSDimitry Andric StackFrameAccess *access) { 32768d75effSDimitry Andric if (stack_top_ == stack_bottom_) 32868d75effSDimitry Andric return false; 32968d75effSDimitry Andric 33068d75effSDimitry Andric uptr bottom = 0; 33168d75effSDimitry Andric if (AddrIsInStack(addr)) { 33268d75effSDimitry Andric bottom = stack_bottom(); 33368d75effSDimitry Andric } else if (has_fake_stack()) { 33468d75effSDimitry Andric bottom = fake_stack()->AddrIsInFakeStack(addr); 33568d75effSDimitry Andric CHECK(bottom); 33668d75effSDimitry Andric access->offset = addr - bottom; 33768d75effSDimitry Andric access->frame_pc = ((uptr*)bottom)[2]; 33868d75effSDimitry Andric access->frame_descr = (const char *)((uptr*)bottom)[1]; 33968d75effSDimitry Andric return true; 34068d75effSDimitry Andric } 34168d75effSDimitry Andric uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr. 34268d75effSDimitry Andric uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY); 34368d75effSDimitry Andric u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); 34468d75effSDimitry Andric u8 *shadow_bottom = (u8*)MemToShadow(bottom); 34568d75effSDimitry Andric 34668d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 34768d75effSDimitry Andric *shadow_ptr != kAsanStackLeftRedzoneMagic) { 34868d75effSDimitry Andric shadow_ptr--; 34968d75effSDimitry Andric mem_ptr -= SHADOW_GRANULARITY; 35068d75effSDimitry Andric } 35168d75effSDimitry Andric 35268d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 35368d75effSDimitry Andric *shadow_ptr == kAsanStackLeftRedzoneMagic) { 35468d75effSDimitry Andric shadow_ptr--; 35568d75effSDimitry Andric mem_ptr -= SHADOW_GRANULARITY; 35668d75effSDimitry Andric } 35768d75effSDimitry Andric 35868d75effSDimitry Andric if (shadow_ptr < shadow_bottom) { 35968d75effSDimitry Andric return false; 36068d75effSDimitry Andric } 36168d75effSDimitry Andric 36268d75effSDimitry Andric uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY); 36368d75effSDimitry Andric CHECK(ptr[0] == kCurrentStackFrameMagic); 36468d75effSDimitry Andric access->offset = addr - (uptr)ptr; 36568d75effSDimitry Andric access->frame_pc = ptr[2]; 36668d75effSDimitry Andric access->frame_descr = (const char*)ptr[1]; 36768d75effSDimitry Andric return true; 36868d75effSDimitry Andric } 36968d75effSDimitry Andric 37068d75effSDimitry Andric uptr AsanThread::GetStackVariableShadowStart(uptr addr) { 37168d75effSDimitry Andric uptr bottom = 0; 37268d75effSDimitry Andric if (AddrIsInStack(addr)) { 37368d75effSDimitry Andric bottom = stack_bottom(); 37468d75effSDimitry Andric } else if (has_fake_stack()) { 37568d75effSDimitry Andric bottom = fake_stack()->AddrIsInFakeStack(addr); 376*e8d8bef9SDimitry Andric if (bottom == 0) { 377*e8d8bef9SDimitry Andric return 0; 378*e8d8bef9SDimitry Andric } 37968d75effSDimitry Andric } else { 38068d75effSDimitry Andric return 0; 38168d75effSDimitry Andric } 38268d75effSDimitry Andric 38368d75effSDimitry Andric uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr. 38468d75effSDimitry Andric u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); 38568d75effSDimitry Andric u8 *shadow_bottom = (u8*)MemToShadow(bottom); 38668d75effSDimitry Andric 38768d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 38868d75effSDimitry Andric (*shadow_ptr != kAsanStackLeftRedzoneMagic && 38968d75effSDimitry Andric *shadow_ptr != kAsanStackMidRedzoneMagic && 39068d75effSDimitry Andric *shadow_ptr != kAsanStackRightRedzoneMagic)) 39168d75effSDimitry Andric shadow_ptr--; 39268d75effSDimitry Andric 39368d75effSDimitry Andric return (uptr)shadow_ptr + 1; 39468d75effSDimitry Andric } 39568d75effSDimitry Andric 39668d75effSDimitry Andric bool AsanThread::AddrIsInStack(uptr addr) { 39768d75effSDimitry Andric const auto bounds = GetStackBounds(); 39868d75effSDimitry Andric return addr >= bounds.bottom && addr < bounds.top; 39968d75effSDimitry Andric } 40068d75effSDimitry Andric 40168d75effSDimitry Andric static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, 40268d75effSDimitry Andric void *addr) { 40368d75effSDimitry Andric AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base); 40468d75effSDimitry Andric AsanThread *t = tctx->thread; 40568d75effSDimitry Andric if (!t) return false; 40668d75effSDimitry Andric if (t->AddrIsInStack((uptr)addr)) return true; 40768d75effSDimitry Andric if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr)) 40868d75effSDimitry Andric return true; 40968d75effSDimitry Andric return false; 41068d75effSDimitry Andric } 41168d75effSDimitry Andric 41268d75effSDimitry Andric AsanThread *GetCurrentThread() { 41368d75effSDimitry Andric if (SANITIZER_RTEMS && !asan_inited) 41468d75effSDimitry Andric return nullptr; 41568d75effSDimitry Andric 41668d75effSDimitry Andric AsanThreadContext *context = 41768d75effSDimitry Andric reinterpret_cast<AsanThreadContext *>(AsanTSDGet()); 41868d75effSDimitry Andric if (!context) { 41968d75effSDimitry Andric if (SANITIZER_ANDROID) { 42068d75effSDimitry Andric // On Android, libc constructor is called _after_ asan_init, and cleans up 42168d75effSDimitry Andric // TSD. Try to figure out if this is still the main thread by the stack 42268d75effSDimitry Andric // address. We are not entirely sure that we have correct main thread 42368d75effSDimitry Andric // limits, so only do this magic on Android, and only if the found thread 42468d75effSDimitry Andric // is the main thread. 42568d75effSDimitry Andric AsanThreadContext *tctx = GetThreadContextByTidLocked(0); 42668d75effSDimitry Andric if (tctx && ThreadStackContainsAddress(tctx, &context)) { 42768d75effSDimitry Andric SetCurrentThread(tctx->thread); 42868d75effSDimitry Andric return tctx->thread; 42968d75effSDimitry Andric } 43068d75effSDimitry Andric } 43168d75effSDimitry Andric return nullptr; 43268d75effSDimitry Andric } 43368d75effSDimitry Andric return context->thread; 43468d75effSDimitry Andric } 43568d75effSDimitry Andric 43668d75effSDimitry Andric void SetCurrentThread(AsanThread *t) { 43768d75effSDimitry Andric CHECK(t->context()); 43868d75effSDimitry Andric VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(), 43968d75effSDimitry Andric (void *)GetThreadSelf()); 44068d75effSDimitry Andric // Make sure we do not reset the current AsanThread. 44168d75effSDimitry Andric CHECK_EQ(0, AsanTSDGet()); 44268d75effSDimitry Andric AsanTSDSet(t->context()); 44368d75effSDimitry Andric CHECK_EQ(t->context(), AsanTSDGet()); 44468d75effSDimitry Andric } 44568d75effSDimitry Andric 44668d75effSDimitry Andric u32 GetCurrentTidOrInvalid() { 44768d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 44868d75effSDimitry Andric return t ? t->tid() : kInvalidTid; 44968d75effSDimitry Andric } 45068d75effSDimitry Andric 45168d75effSDimitry Andric AsanThread *FindThreadByStackAddress(uptr addr) { 45268d75effSDimitry Andric asanThreadRegistry().CheckLocked(); 45368d75effSDimitry Andric AsanThreadContext *tctx = static_cast<AsanThreadContext *>( 45468d75effSDimitry Andric asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress, 45568d75effSDimitry Andric (void *)addr)); 45668d75effSDimitry Andric return tctx ? tctx->thread : nullptr; 45768d75effSDimitry Andric } 45868d75effSDimitry Andric 45968d75effSDimitry Andric void EnsureMainThreadIDIsCorrect() { 46068d75effSDimitry Andric AsanThreadContext *context = 46168d75effSDimitry Andric reinterpret_cast<AsanThreadContext *>(AsanTSDGet()); 46268d75effSDimitry Andric if (context && (context->tid == 0)) 46368d75effSDimitry Andric context->os_id = GetTid(); 46468d75effSDimitry Andric } 46568d75effSDimitry Andric 46668d75effSDimitry Andric __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) { 46768d75effSDimitry Andric __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( 46868d75effSDimitry Andric __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); 46968d75effSDimitry Andric if (!context) return nullptr; 47068d75effSDimitry Andric return context->thread; 47168d75effSDimitry Andric } 47268d75effSDimitry Andric } // namespace __asan 47368d75effSDimitry Andric 47468d75effSDimitry Andric // --- Implementation of LSan-specific functions --- {{{1 47568d75effSDimitry Andric namespace __lsan { 47668d75effSDimitry Andric bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, 47768d75effSDimitry Andric uptr *tls_begin, uptr *tls_end, uptr *cache_begin, 47868d75effSDimitry Andric uptr *cache_end, DTLS **dtls) { 47968d75effSDimitry Andric __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); 48068d75effSDimitry Andric if (!t) return false; 48168d75effSDimitry Andric *stack_begin = t->stack_bottom(); 48268d75effSDimitry Andric *stack_end = t->stack_top(); 48368d75effSDimitry Andric *tls_begin = t->tls_begin(); 48468d75effSDimitry Andric *tls_end = t->tls_end(); 48568d75effSDimitry Andric // ASan doesn't keep allocator caches in TLS, so these are unused. 48668d75effSDimitry Andric *cache_begin = 0; 48768d75effSDimitry Andric *cache_end = 0; 48868d75effSDimitry Andric *dtls = t->dtls(); 48968d75effSDimitry Andric return true; 49068d75effSDimitry Andric } 49168d75effSDimitry Andric 4925ffd83dbSDimitry Andric void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {} 4935ffd83dbSDimitry Andric 49468d75effSDimitry Andric void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, 49568d75effSDimitry Andric void *arg) { 49668d75effSDimitry Andric __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); 49768d75effSDimitry Andric if (t && t->has_fake_stack()) 49868d75effSDimitry Andric t->fake_stack()->ForEachFakeFrame(callback, arg); 49968d75effSDimitry Andric } 50068d75effSDimitry Andric 50168d75effSDimitry Andric void LockThreadRegistry() { 50268d75effSDimitry Andric __asan::asanThreadRegistry().Lock(); 50368d75effSDimitry Andric } 50468d75effSDimitry Andric 50568d75effSDimitry Andric void UnlockThreadRegistry() { 50668d75effSDimitry Andric __asan::asanThreadRegistry().Unlock(); 50768d75effSDimitry Andric } 50868d75effSDimitry Andric 50968d75effSDimitry Andric ThreadRegistry *GetThreadRegistryLocked() { 51068d75effSDimitry Andric __asan::asanThreadRegistry().CheckLocked(); 51168d75effSDimitry Andric return &__asan::asanThreadRegistry(); 51268d75effSDimitry Andric } 51368d75effSDimitry Andric 51468d75effSDimitry Andric void EnsureMainThreadIDIsCorrect() { 51568d75effSDimitry Andric __asan::EnsureMainThreadIDIsCorrect(); 51668d75effSDimitry Andric } 51768d75effSDimitry Andric } // namespace __lsan 51868d75effSDimitry Andric 51968d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1 52068d75effSDimitry Andric using namespace __asan; 52168d75effSDimitry Andric 52268d75effSDimitry Andric extern "C" { 52368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 52468d75effSDimitry Andric void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom, 52568d75effSDimitry Andric uptr size) { 52668d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 52768d75effSDimitry Andric if (!t) { 52868d75effSDimitry Andric VReport(1, "__asan_start_switch_fiber called from unknown thread\n"); 52968d75effSDimitry Andric return; 53068d75effSDimitry Andric } 53168d75effSDimitry Andric t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size); 53268d75effSDimitry Andric } 53368d75effSDimitry Andric 53468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 53568d75effSDimitry Andric void __sanitizer_finish_switch_fiber(void* fakestack, 53668d75effSDimitry Andric const void **bottom_old, 53768d75effSDimitry Andric uptr *size_old) { 53868d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 53968d75effSDimitry Andric if (!t) { 54068d75effSDimitry Andric VReport(1, "__asan_finish_switch_fiber called from unknown thread\n"); 54168d75effSDimitry Andric return; 54268d75effSDimitry Andric } 54368d75effSDimitry Andric t->FinishSwitchFiber((FakeStack*)fakestack, 54468d75effSDimitry Andric (uptr*)bottom_old, 54568d75effSDimitry Andric (uptr*)size_old); 54668d75effSDimitry Andric } 54768d75effSDimitry Andric } 548