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. 63*fe6060f1SDimitry Andric asan_thread_registry = 64*fe6060f1SDimitry Andric new (thread_registry_placeholder) ThreadRegistry(GetAsanThreadContext); 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 103*fe6060f1SDimitry Andric bool was_running = 104*fe6060f1SDimitry Andric (asanThreadRegistry().FinishThread(tid) == ThreadStatusRunning); 105*fe6060f1SDimitry Andric if (was_running) { 106*fe6060f1SDimitry Andric if (AsanThread *thread = GetCurrentThread()) 107*fe6060f1SDimitry Andric CHECK_EQ(this, thread); 10868d75effSDimitry Andric malloc_storage().CommitBack(); 109*fe6060f1SDimitry Andric if (common_flags()->use_sigaltstack) 110*fe6060f1SDimitry Andric UnsetAlternateSignalStack(); 11168d75effSDimitry Andric FlushToDeadThreadStats(&stats_); 11268d75effSDimitry Andric // We also clear the shadow on thread destruction because 11368d75effSDimitry Andric // some code may still be executing in later TSD destructors 11468d75effSDimitry Andric // and we don't want it to have any poisoned stack. 11568d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 11668d75effSDimitry Andric DeleteFakeStack(tid); 117*fe6060f1SDimitry Andric } else { 118*fe6060f1SDimitry Andric CHECK_NE(this, GetCurrentThread()); 119*fe6060f1SDimitry Andric } 12068d75effSDimitry Andric uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached()); 12168d75effSDimitry Andric UnmapOrDie(this, size); 122*fe6060f1SDimitry Andric if (was_running) 12368d75effSDimitry Andric DTLS_Destroy(); 12468d75effSDimitry Andric } 12568d75effSDimitry Andric 12668d75effSDimitry Andric void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, 12768d75effSDimitry Andric uptr size) { 12868d75effSDimitry Andric if (atomic_load(&stack_switching_, memory_order_relaxed)) { 12968d75effSDimitry Andric Report("ERROR: starting fiber switch while in fiber switch\n"); 13068d75effSDimitry Andric Die(); 13168d75effSDimitry Andric } 13268d75effSDimitry Andric 13368d75effSDimitry Andric next_stack_bottom_ = bottom; 13468d75effSDimitry Andric next_stack_top_ = bottom + size; 13568d75effSDimitry Andric atomic_store(&stack_switching_, 1, memory_order_release); 13668d75effSDimitry Andric 13768d75effSDimitry Andric FakeStack *current_fake_stack = fake_stack_; 13868d75effSDimitry Andric if (fake_stack_save) 13968d75effSDimitry Andric *fake_stack_save = fake_stack_; 14068d75effSDimitry Andric fake_stack_ = nullptr; 14168d75effSDimitry Andric SetTLSFakeStack(nullptr); 14268d75effSDimitry Andric // if fake_stack_save is null, the fiber will die, delete the fakestack 14368d75effSDimitry Andric if (!fake_stack_save && current_fake_stack) 14468d75effSDimitry Andric current_fake_stack->Destroy(this->tid()); 14568d75effSDimitry Andric } 14668d75effSDimitry Andric 14768d75effSDimitry Andric void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, 14868d75effSDimitry Andric uptr *bottom_old, 14968d75effSDimitry Andric uptr *size_old) { 15068d75effSDimitry Andric if (!atomic_load(&stack_switching_, memory_order_relaxed)) { 15168d75effSDimitry Andric Report("ERROR: finishing a fiber switch that has not started\n"); 15268d75effSDimitry Andric Die(); 15368d75effSDimitry Andric } 15468d75effSDimitry Andric 15568d75effSDimitry Andric if (fake_stack_save) { 15668d75effSDimitry Andric SetTLSFakeStack(fake_stack_save); 15768d75effSDimitry Andric fake_stack_ = fake_stack_save; 15868d75effSDimitry Andric } 15968d75effSDimitry Andric 16068d75effSDimitry Andric if (bottom_old) 16168d75effSDimitry Andric *bottom_old = stack_bottom_; 16268d75effSDimitry Andric if (size_old) 16368d75effSDimitry Andric *size_old = stack_top_ - stack_bottom_; 16468d75effSDimitry Andric stack_bottom_ = next_stack_bottom_; 16568d75effSDimitry Andric stack_top_ = next_stack_top_; 16668d75effSDimitry Andric atomic_store(&stack_switching_, 0, memory_order_release); 16768d75effSDimitry Andric next_stack_top_ = 0; 16868d75effSDimitry Andric next_stack_bottom_ = 0; 16968d75effSDimitry Andric } 17068d75effSDimitry Andric 17168d75effSDimitry Andric inline AsanThread::StackBounds AsanThread::GetStackBounds() const { 17268d75effSDimitry Andric if (!atomic_load(&stack_switching_, memory_order_acquire)) { 17368d75effSDimitry Andric // Make sure the stack bounds are fully initialized. 17468d75effSDimitry Andric if (stack_bottom_ >= stack_top_) return {0, 0}; 17568d75effSDimitry Andric return {stack_bottom_, stack_top_}; 17668d75effSDimitry Andric } 17768d75effSDimitry Andric char local; 17868d75effSDimitry Andric const uptr cur_stack = (uptr)&local; 17968d75effSDimitry Andric // Note: need to check next stack first, because FinishSwitchFiber 18068d75effSDimitry Andric // may be in process of overwriting stack_top_/bottom_. But in such case 18168d75effSDimitry Andric // we are already on the next stack. 18268d75effSDimitry Andric if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_) 18368d75effSDimitry Andric return {next_stack_bottom_, next_stack_top_}; 18468d75effSDimitry Andric return {stack_bottom_, stack_top_}; 18568d75effSDimitry Andric } 18668d75effSDimitry Andric 18768d75effSDimitry Andric uptr AsanThread::stack_top() { 18868d75effSDimitry Andric return GetStackBounds().top; 18968d75effSDimitry Andric } 19068d75effSDimitry Andric 19168d75effSDimitry Andric uptr AsanThread::stack_bottom() { 19268d75effSDimitry Andric return GetStackBounds().bottom; 19368d75effSDimitry Andric } 19468d75effSDimitry Andric 19568d75effSDimitry Andric uptr AsanThread::stack_size() { 19668d75effSDimitry Andric const auto bounds = GetStackBounds(); 19768d75effSDimitry Andric return bounds.top - bounds.bottom; 19868d75effSDimitry Andric } 19968d75effSDimitry Andric 200e8d8bef9SDimitry Andric // We want to create the FakeStack lazily on the first use, but not earlier 20168d75effSDimitry Andric // than the stack size is known and the procedure has to be async-signal safe. 20268d75effSDimitry Andric FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { 20368d75effSDimitry Andric uptr stack_size = this->stack_size(); 20468d75effSDimitry Andric if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. 20568d75effSDimitry Andric return nullptr; 20668d75effSDimitry Andric uptr old_val = 0; 20768d75effSDimitry Andric // fake_stack_ has 3 states: 20868d75effSDimitry Andric // 0 -- not initialized 20968d75effSDimitry Andric // 1 -- being initialized 21068d75effSDimitry Andric // ptr -- initialized 21168d75effSDimitry Andric // This CAS checks if the state was 0 and if so changes it to state 1, 21268d75effSDimitry Andric // if that was successful, it initializes the pointer. 21368d75effSDimitry Andric if (atomic_compare_exchange_strong( 21468d75effSDimitry Andric reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL, 21568d75effSDimitry Andric memory_order_relaxed)) { 21668d75effSDimitry Andric uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size)); 21768d75effSDimitry Andric CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log); 21868d75effSDimitry Andric stack_size_log = 21968d75effSDimitry Andric Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log)); 22068d75effSDimitry Andric stack_size_log = 22168d75effSDimitry Andric Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log)); 22268d75effSDimitry Andric fake_stack_ = FakeStack::Create(stack_size_log); 223e8d8bef9SDimitry Andric DCHECK_EQ(GetCurrentThread(), this); 22468d75effSDimitry Andric SetTLSFakeStack(fake_stack_); 22568d75effSDimitry Andric return fake_stack_; 22668d75effSDimitry Andric } 22768d75effSDimitry Andric return nullptr; 22868d75effSDimitry Andric } 22968d75effSDimitry Andric 23068d75effSDimitry Andric void AsanThread::Init(const InitOptions *options) { 231*fe6060f1SDimitry Andric DCHECK_NE(tid(), kInvalidTid); 23268d75effSDimitry Andric next_stack_top_ = next_stack_bottom_ = 0; 23368d75effSDimitry Andric atomic_store(&stack_switching_, false, memory_order_release); 23468d75effSDimitry Andric CHECK_EQ(this->stack_size(), 0U); 23568d75effSDimitry Andric SetThreadStackAndTls(options); 23668d75effSDimitry Andric if (stack_top_ != stack_bottom_) { 23768d75effSDimitry Andric CHECK_GT(this->stack_size(), 0U); 23868d75effSDimitry Andric CHECK(AddrIsInMem(stack_bottom_)); 23968d75effSDimitry Andric CHECK(AddrIsInMem(stack_top_ - 1)); 24068d75effSDimitry Andric } 24168d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 24268d75effSDimitry Andric fake_stack_ = nullptr; 243e8d8bef9SDimitry Andric if (__asan_option_detect_stack_use_after_return && 244e8d8bef9SDimitry Andric tid() == GetCurrentTidOrInvalid()) { 245e8d8bef9SDimitry Andric // AsyncSignalSafeLazyInitFakeStack makes use of threadlocals and must be 246e8d8bef9SDimitry Andric // called from the context of the thread it is initializing, not its parent. 247e8d8bef9SDimitry Andric // Most platforms call AsanThread::Init on the newly-spawned thread, but 248e8d8bef9SDimitry Andric // Fuchsia calls this function from the parent thread. To support that 249e8d8bef9SDimitry Andric // approach, we avoid calling AsyncSignalSafeLazyInitFakeStack here; it will 250e8d8bef9SDimitry Andric // be called by the new thread when it first attempts to access the fake 251e8d8bef9SDimitry Andric // stack. 25268d75effSDimitry Andric AsyncSignalSafeLazyInitFakeStack(); 253e8d8bef9SDimitry Andric } 25468d75effSDimitry Andric int local = 0; 25568d75effSDimitry Andric VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), 25668d75effSDimitry Andric (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_, 25768d75effSDimitry Andric &local); 25868d75effSDimitry Andric } 25968d75effSDimitry Andric 260*fe6060f1SDimitry Andric // Fuchsia doesn't use ThreadStart. 261*fe6060f1SDimitry Andric // asan_fuchsia.c definies CreateMainThread and SetThreadStackAndTls. 262*fe6060f1SDimitry Andric #if !SANITIZER_FUCHSIA 26368d75effSDimitry Andric 264e8d8bef9SDimitry Andric thread_return_t AsanThread::ThreadStart(tid_t os_id) { 26568d75effSDimitry Andric Init(); 26668d75effSDimitry Andric asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr); 26768d75effSDimitry Andric 26868d75effSDimitry Andric if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); 26968d75effSDimitry Andric 27068d75effSDimitry Andric if (!start_routine_) { 27168d75effSDimitry Andric // start_routine_ == 0 if we're on the main thread or on one of the 27268d75effSDimitry Andric // OS X libdispatch worker threads. But nobody is supposed to call 27368d75effSDimitry Andric // ThreadStart() for the worker threads. 27468d75effSDimitry Andric CHECK_EQ(tid(), 0); 27568d75effSDimitry Andric return 0; 27668d75effSDimitry Andric } 27768d75effSDimitry Andric 27868d75effSDimitry Andric thread_return_t res = start_routine_(arg_); 27968d75effSDimitry Andric 28068d75effSDimitry Andric // On POSIX systems we defer this to the TSD destructor. LSan will consider 28168d75effSDimitry Andric // the thread's memory as non-live from the moment we call Destroy(), even 28268d75effSDimitry Andric // though that memory might contain pointers to heap objects which will be 28368d75effSDimitry Andric // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before 28468d75effSDimitry Andric // the TSD destructors have run might cause false positives in LSan. 28568d75effSDimitry Andric if (!SANITIZER_POSIX) 28668d75effSDimitry Andric this->Destroy(); 28768d75effSDimitry Andric 28868d75effSDimitry Andric return res; 28968d75effSDimitry Andric } 29068d75effSDimitry Andric 29168d75effSDimitry Andric AsanThread *CreateMainThread() { 29268d75effSDimitry Andric AsanThread *main_thread = AsanThread::Create( 293*fe6060f1SDimitry Andric /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ kMainTid, 29468d75effSDimitry Andric /* stack */ nullptr, /* detached */ true); 29568d75effSDimitry Andric SetCurrentThread(main_thread); 296e8d8bef9SDimitry Andric main_thread->ThreadStart(internal_getpid()); 29768d75effSDimitry Andric return main_thread; 29868d75effSDimitry Andric } 29968d75effSDimitry Andric 30068d75effSDimitry Andric // This implementation doesn't use the argument, which is just passed down 30168d75effSDimitry Andric // from the caller of Init (which see, above). It's only there to support 30268d75effSDimitry Andric // OS-specific implementations that need more information passed through. 30368d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const InitOptions *options) { 30468d75effSDimitry Andric DCHECK_EQ(options, nullptr); 30568d75effSDimitry Andric uptr tls_size = 0; 30668d75effSDimitry Andric uptr stack_size = 0; 307*fe6060f1SDimitry Andric GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size, 308*fe6060f1SDimitry Andric &tls_begin_, &tls_size); 309*fe6060f1SDimitry Andric stack_top_ = RoundDownTo(stack_bottom_ + stack_size, SHADOW_GRANULARITY); 31068d75effSDimitry Andric tls_end_ = tls_begin_ + tls_size; 31168d75effSDimitry Andric dtls_ = DTLS_Get(); 31268d75effSDimitry Andric 31368d75effSDimitry Andric if (stack_top_ != stack_bottom_) { 31468d75effSDimitry Andric int local; 31568d75effSDimitry Andric CHECK(AddrIsInStack((uptr)&local)); 31668d75effSDimitry Andric } 31768d75effSDimitry Andric } 31868d75effSDimitry Andric 319*fe6060f1SDimitry Andric #endif // !SANITIZER_FUCHSIA 32068d75effSDimitry Andric 32168d75effSDimitry Andric void AsanThread::ClearShadowForThreadStackAndTLS() { 32268d75effSDimitry Andric if (stack_top_ != stack_bottom_) 32368d75effSDimitry Andric PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); 32468d75effSDimitry Andric if (tls_begin_ != tls_end_) { 32568d75effSDimitry Andric uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY); 32668d75effSDimitry Andric uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY); 32768d75effSDimitry Andric FastPoisonShadowPartialRightRedzone(tls_begin_aligned, 32868d75effSDimitry Andric tls_end_ - tls_begin_aligned, 32968d75effSDimitry Andric tls_end_aligned - tls_end_, 0); 33068d75effSDimitry Andric } 33168d75effSDimitry Andric } 33268d75effSDimitry Andric 33368d75effSDimitry Andric bool AsanThread::GetStackFrameAccessByAddr(uptr addr, 33468d75effSDimitry Andric StackFrameAccess *access) { 33568d75effSDimitry Andric if (stack_top_ == stack_bottom_) 33668d75effSDimitry Andric return false; 33768d75effSDimitry Andric 33868d75effSDimitry Andric uptr bottom = 0; 33968d75effSDimitry Andric if (AddrIsInStack(addr)) { 34068d75effSDimitry Andric bottom = stack_bottom(); 341*fe6060f1SDimitry Andric } else if (FakeStack *fake_stack = get_fake_stack()) { 342*fe6060f1SDimitry Andric bottom = fake_stack->AddrIsInFakeStack(addr); 34368d75effSDimitry Andric CHECK(bottom); 34468d75effSDimitry Andric access->offset = addr - bottom; 34568d75effSDimitry Andric access->frame_pc = ((uptr*)bottom)[2]; 34668d75effSDimitry Andric access->frame_descr = (const char *)((uptr*)bottom)[1]; 34768d75effSDimitry Andric return true; 34868d75effSDimitry Andric } 34968d75effSDimitry Andric uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr. 35068d75effSDimitry Andric uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY); 35168d75effSDimitry Andric u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); 35268d75effSDimitry Andric u8 *shadow_bottom = (u8*)MemToShadow(bottom); 35368d75effSDimitry Andric 35468d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 35568d75effSDimitry Andric *shadow_ptr != kAsanStackLeftRedzoneMagic) { 35668d75effSDimitry Andric shadow_ptr--; 35768d75effSDimitry Andric mem_ptr -= SHADOW_GRANULARITY; 35868d75effSDimitry Andric } 35968d75effSDimitry Andric 36068d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 36168d75effSDimitry Andric *shadow_ptr == kAsanStackLeftRedzoneMagic) { 36268d75effSDimitry Andric shadow_ptr--; 36368d75effSDimitry Andric mem_ptr -= SHADOW_GRANULARITY; 36468d75effSDimitry Andric } 36568d75effSDimitry Andric 36668d75effSDimitry Andric if (shadow_ptr < shadow_bottom) { 36768d75effSDimitry Andric return false; 36868d75effSDimitry Andric } 36968d75effSDimitry Andric 37068d75effSDimitry Andric uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY); 37168d75effSDimitry Andric CHECK(ptr[0] == kCurrentStackFrameMagic); 37268d75effSDimitry Andric access->offset = addr - (uptr)ptr; 37368d75effSDimitry Andric access->frame_pc = ptr[2]; 37468d75effSDimitry Andric access->frame_descr = (const char*)ptr[1]; 37568d75effSDimitry Andric return true; 37668d75effSDimitry Andric } 37768d75effSDimitry Andric 37868d75effSDimitry Andric uptr AsanThread::GetStackVariableShadowStart(uptr addr) { 37968d75effSDimitry Andric uptr bottom = 0; 38068d75effSDimitry Andric if (AddrIsInStack(addr)) { 38168d75effSDimitry Andric bottom = stack_bottom(); 382*fe6060f1SDimitry Andric } else if (FakeStack *fake_stack = get_fake_stack()) { 383*fe6060f1SDimitry Andric bottom = fake_stack->AddrIsInFakeStack(addr); 384e8d8bef9SDimitry Andric if (bottom == 0) { 385e8d8bef9SDimitry Andric return 0; 386e8d8bef9SDimitry Andric } 38768d75effSDimitry Andric } else { 38868d75effSDimitry Andric return 0; 38968d75effSDimitry Andric } 39068d75effSDimitry Andric 39168d75effSDimitry Andric uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr. 39268d75effSDimitry Andric u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); 39368d75effSDimitry Andric u8 *shadow_bottom = (u8*)MemToShadow(bottom); 39468d75effSDimitry Andric 39568d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 39668d75effSDimitry Andric (*shadow_ptr != kAsanStackLeftRedzoneMagic && 39768d75effSDimitry Andric *shadow_ptr != kAsanStackMidRedzoneMagic && 39868d75effSDimitry Andric *shadow_ptr != kAsanStackRightRedzoneMagic)) 39968d75effSDimitry Andric shadow_ptr--; 40068d75effSDimitry Andric 40168d75effSDimitry Andric return (uptr)shadow_ptr + 1; 40268d75effSDimitry Andric } 40368d75effSDimitry Andric 40468d75effSDimitry Andric bool AsanThread::AddrIsInStack(uptr addr) { 40568d75effSDimitry Andric const auto bounds = GetStackBounds(); 40668d75effSDimitry Andric return addr >= bounds.bottom && addr < bounds.top; 40768d75effSDimitry Andric } 40868d75effSDimitry Andric 40968d75effSDimitry Andric static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, 41068d75effSDimitry Andric void *addr) { 41168d75effSDimitry Andric AsanThreadContext *tctx = static_cast<AsanThreadContext *>(tctx_base); 41268d75effSDimitry Andric AsanThread *t = tctx->thread; 413*fe6060f1SDimitry Andric if (!t) 41468d75effSDimitry Andric return false; 415*fe6060f1SDimitry Andric if (t->AddrIsInStack((uptr)addr)) 416*fe6060f1SDimitry Andric return true; 417*fe6060f1SDimitry Andric FakeStack *fake_stack = t->get_fake_stack(); 418*fe6060f1SDimitry Andric if (!fake_stack) 419*fe6060f1SDimitry Andric return false; 420*fe6060f1SDimitry Andric return fake_stack->AddrIsInFakeStack((uptr)addr); 42168d75effSDimitry Andric } 42268d75effSDimitry Andric 42368d75effSDimitry Andric AsanThread *GetCurrentThread() { 42468d75effSDimitry Andric AsanThreadContext *context = 42568d75effSDimitry Andric reinterpret_cast<AsanThreadContext *>(AsanTSDGet()); 42668d75effSDimitry Andric if (!context) { 42768d75effSDimitry Andric if (SANITIZER_ANDROID) { 42868d75effSDimitry Andric // On Android, libc constructor is called _after_ asan_init, and cleans up 42968d75effSDimitry Andric // TSD. Try to figure out if this is still the main thread by the stack 43068d75effSDimitry Andric // address. We are not entirely sure that we have correct main thread 43168d75effSDimitry Andric // limits, so only do this magic on Android, and only if the found thread 43268d75effSDimitry Andric // is the main thread. 433*fe6060f1SDimitry Andric AsanThreadContext *tctx = GetThreadContextByTidLocked(kMainTid); 43468d75effSDimitry Andric if (tctx && ThreadStackContainsAddress(tctx, &context)) { 43568d75effSDimitry Andric SetCurrentThread(tctx->thread); 43668d75effSDimitry Andric return tctx->thread; 43768d75effSDimitry Andric } 43868d75effSDimitry Andric } 43968d75effSDimitry Andric return nullptr; 44068d75effSDimitry Andric } 44168d75effSDimitry Andric return context->thread; 44268d75effSDimitry Andric } 44368d75effSDimitry Andric 44468d75effSDimitry Andric void SetCurrentThread(AsanThread *t) { 44568d75effSDimitry Andric CHECK(t->context()); 44668d75effSDimitry Andric VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(), 44768d75effSDimitry Andric (void *)GetThreadSelf()); 44868d75effSDimitry Andric // Make sure we do not reset the current AsanThread. 44968d75effSDimitry Andric CHECK_EQ(0, AsanTSDGet()); 45068d75effSDimitry Andric AsanTSDSet(t->context()); 45168d75effSDimitry Andric CHECK_EQ(t->context(), AsanTSDGet()); 45268d75effSDimitry Andric } 45368d75effSDimitry Andric 45468d75effSDimitry Andric u32 GetCurrentTidOrInvalid() { 45568d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 45668d75effSDimitry Andric return t ? t->tid() : kInvalidTid; 45768d75effSDimitry Andric } 45868d75effSDimitry Andric 45968d75effSDimitry Andric AsanThread *FindThreadByStackAddress(uptr addr) { 46068d75effSDimitry Andric asanThreadRegistry().CheckLocked(); 46168d75effSDimitry Andric AsanThreadContext *tctx = static_cast<AsanThreadContext *>( 46268d75effSDimitry Andric asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress, 46368d75effSDimitry Andric (void *)addr)); 46468d75effSDimitry Andric return tctx ? tctx->thread : nullptr; 46568d75effSDimitry Andric } 46668d75effSDimitry Andric 46768d75effSDimitry Andric void EnsureMainThreadIDIsCorrect() { 46868d75effSDimitry Andric AsanThreadContext *context = 46968d75effSDimitry Andric reinterpret_cast<AsanThreadContext *>(AsanTSDGet()); 470*fe6060f1SDimitry Andric if (context && (context->tid == kMainTid)) 47168d75effSDimitry Andric context->os_id = GetTid(); 47268d75effSDimitry Andric } 47368d75effSDimitry Andric 47468d75effSDimitry Andric __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) { 47568d75effSDimitry Andric __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( 47668d75effSDimitry Andric __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); 47768d75effSDimitry Andric if (!context) return nullptr; 47868d75effSDimitry Andric return context->thread; 47968d75effSDimitry Andric } 48068d75effSDimitry Andric } // namespace __asan 48168d75effSDimitry Andric 48268d75effSDimitry Andric // --- Implementation of LSan-specific functions --- {{{1 48368d75effSDimitry Andric namespace __lsan { 48468d75effSDimitry Andric bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, 48568d75effSDimitry Andric uptr *tls_begin, uptr *tls_end, uptr *cache_begin, 48668d75effSDimitry Andric uptr *cache_end, DTLS **dtls) { 48768d75effSDimitry Andric __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); 48868d75effSDimitry Andric if (!t) return false; 48968d75effSDimitry Andric *stack_begin = t->stack_bottom(); 49068d75effSDimitry Andric *stack_end = t->stack_top(); 49168d75effSDimitry Andric *tls_begin = t->tls_begin(); 49268d75effSDimitry Andric *tls_end = t->tls_end(); 49368d75effSDimitry Andric // ASan doesn't keep allocator caches in TLS, so these are unused. 49468d75effSDimitry Andric *cache_begin = 0; 49568d75effSDimitry Andric *cache_end = 0; 49668d75effSDimitry Andric *dtls = t->dtls(); 49768d75effSDimitry Andric return true; 49868d75effSDimitry Andric } 49968d75effSDimitry Andric 5005ffd83dbSDimitry Andric void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {} 5015ffd83dbSDimitry Andric 50268d75effSDimitry Andric void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, 50368d75effSDimitry Andric void *arg) { 50468d75effSDimitry Andric __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); 505*fe6060f1SDimitry Andric if (!t) 506*fe6060f1SDimitry Andric return; 507*fe6060f1SDimitry Andric __asan::FakeStack *fake_stack = t->get_fake_stack(); 508*fe6060f1SDimitry Andric if (!fake_stack) 509*fe6060f1SDimitry Andric return; 510*fe6060f1SDimitry Andric fake_stack->ForEachFakeFrame(callback, arg); 51168d75effSDimitry Andric } 51268d75effSDimitry Andric 51368d75effSDimitry Andric void LockThreadRegistry() { 51468d75effSDimitry Andric __asan::asanThreadRegistry().Lock(); 51568d75effSDimitry Andric } 51668d75effSDimitry Andric 51768d75effSDimitry Andric void UnlockThreadRegistry() { 51868d75effSDimitry Andric __asan::asanThreadRegistry().Unlock(); 51968d75effSDimitry Andric } 52068d75effSDimitry Andric 52168d75effSDimitry Andric ThreadRegistry *GetThreadRegistryLocked() { 52268d75effSDimitry Andric __asan::asanThreadRegistry().CheckLocked(); 52368d75effSDimitry Andric return &__asan::asanThreadRegistry(); 52468d75effSDimitry Andric } 52568d75effSDimitry Andric 52668d75effSDimitry Andric void EnsureMainThreadIDIsCorrect() { 52768d75effSDimitry Andric __asan::EnsureMainThreadIDIsCorrect(); 52868d75effSDimitry Andric } 52968d75effSDimitry Andric } // namespace __lsan 53068d75effSDimitry Andric 53168d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1 53268d75effSDimitry Andric using namespace __asan; 53368d75effSDimitry Andric 53468d75effSDimitry Andric extern "C" { 53568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 53668d75effSDimitry Andric void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom, 53768d75effSDimitry Andric uptr size) { 53868d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 53968d75effSDimitry Andric if (!t) { 54068d75effSDimitry Andric VReport(1, "__asan_start_switch_fiber called from unknown thread\n"); 54168d75effSDimitry Andric return; 54268d75effSDimitry Andric } 54368d75effSDimitry Andric t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size); 54468d75effSDimitry Andric } 54568d75effSDimitry Andric 54668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 54768d75effSDimitry Andric void __sanitizer_finish_switch_fiber(void* fakestack, 54868d75effSDimitry Andric const void **bottom_old, 54968d75effSDimitry Andric uptr *size_old) { 55068d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 55168d75effSDimitry Andric if (!t) { 55268d75effSDimitry Andric VReport(1, "__asan_finish_switch_fiber called from unknown thread\n"); 55368d75effSDimitry Andric return; 55468d75effSDimitry Andric } 55568d75effSDimitry Andric t->FinishSwitchFiber((FakeStack*)fakestack, 55668d75effSDimitry Andric (uptr*)bottom_old, 55768d75effSDimitry Andric (uptr*)size_old); 55868d75effSDimitry Andric } 55968d75effSDimitry Andric } 560