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 //===----------------------------------------------------------------------===// 1306c3fb27SDimitry Andric #include "asan_thread.h" 1406c3fb27SDimitry Andric 1568d75effSDimitry Andric #include "asan_allocator.h" 1668d75effSDimitry Andric #include "asan_interceptors.h" 1706c3fb27SDimitry Andric #include "asan_mapping.h" 1868d75effSDimitry Andric #include "asan_poisoning.h" 1968d75effSDimitry Andric #include "asan_stack.h" 2006c3fb27SDimitry Andric #include "lsan/lsan_common.h" 2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h" 2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_tls_get_addr.h" 2568d75effSDimitry Andric 2668d75effSDimitry Andric namespace __asan { 2768d75effSDimitry Andric 2868d75effSDimitry Andric // AsanThreadContext implementation. 2968d75effSDimitry Andric 3068d75effSDimitry Andric void AsanThreadContext::OnCreated(void *arg) { 3168d75effSDimitry Andric CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs *>(arg); 3268d75effSDimitry Andric if (args->stack) 3368d75effSDimitry Andric stack_id = StackDepotPut(*args->stack); 3468d75effSDimitry Andric thread = args->thread; 3568d75effSDimitry Andric thread->set_context(this); 3668d75effSDimitry Andric } 3768d75effSDimitry Andric 3868d75effSDimitry Andric void AsanThreadContext::OnFinished() { 3968d75effSDimitry Andric // Drop the link to the AsanThread object. 4068d75effSDimitry Andric thread = nullptr; 4168d75effSDimitry Andric } 4268d75effSDimitry Andric 4368d75effSDimitry Andric static ThreadRegistry *asan_thread_registry; 4406c3fb27SDimitry Andric static ThreadArgRetval *thread_data; 4568d75effSDimitry Andric 46349cc55cSDimitry Andric static Mutex mu_for_thread_context; 47*0fca6ea1SDimitry Andric // TODO(leonardchan@): It should be possible to make LowLevelAllocator 48*0fca6ea1SDimitry Andric // threadsafe and consolidate this one into the GlobalLoweLevelAllocator. 49*0fca6ea1SDimitry Andric // We should be able to do something similar to what's in 50*0fca6ea1SDimitry Andric // sanitizer_stack_store.cpp. 51*0fca6ea1SDimitry Andric static LowLevelAllocator allocator_for_thread_context; 5268d75effSDimitry Andric 5368d75effSDimitry Andric static ThreadContextBase *GetAsanThreadContext(u32 tid) { 54349cc55cSDimitry Andric Lock lock(&mu_for_thread_context); 55*0fca6ea1SDimitry Andric return new (allocator_for_thread_context) AsanThreadContext(tid); 5668d75effSDimitry Andric } 5768d75effSDimitry Andric 5806c3fb27SDimitry Andric static void InitThreads() { 5968d75effSDimitry Andric static bool initialized; 6068d75effSDimitry Andric // Don't worry about thread_safety - this should be called when there is 6168d75effSDimitry Andric // a single thread. 6206c3fb27SDimitry Andric if (LIKELY(initialized)) 6306c3fb27SDimitry Andric return; 6468d75effSDimitry Andric // Never reuse ASan threads: we store pointer to AsanThreadContext 6568d75effSDimitry Andric // in TSD and can't reliably tell when no more TSD destructors will 6668d75effSDimitry Andric // be called. It would be wrong to reuse AsanThreadContext for another 6768d75effSDimitry Andric // thread before all TSD destructors will be called for it. 6806c3fb27SDimitry Andric 6906c3fb27SDimitry Andric // MIPS requires aligned address 70*0fca6ea1SDimitry Andric alignas(alignof(ThreadRegistry)) static char 71*0fca6ea1SDimitry Andric thread_registry_placeholder[sizeof(ThreadRegistry)]; 72*0fca6ea1SDimitry Andric alignas(alignof(ThreadArgRetval)) static char 73*0fca6ea1SDimitry Andric thread_data_placeholder[sizeof(ThreadArgRetval)]; 7406c3fb27SDimitry Andric 75fe6060f1SDimitry Andric asan_thread_registry = 76fe6060f1SDimitry Andric new (thread_registry_placeholder) ThreadRegistry(GetAsanThreadContext); 7706c3fb27SDimitry Andric thread_data = new (thread_data_placeholder) ThreadArgRetval(); 7868d75effSDimitry Andric initialized = true; 7968d75effSDimitry Andric } 8006c3fb27SDimitry Andric 8106c3fb27SDimitry Andric ThreadRegistry &asanThreadRegistry() { 8206c3fb27SDimitry Andric InitThreads(); 8368d75effSDimitry Andric return *asan_thread_registry; 8468d75effSDimitry Andric } 8568d75effSDimitry Andric 8606c3fb27SDimitry Andric ThreadArgRetval &asanThreadArgRetval() { 8706c3fb27SDimitry Andric InitThreads(); 8806c3fb27SDimitry Andric return *thread_data; 8906c3fb27SDimitry Andric } 9006c3fb27SDimitry Andric 9168d75effSDimitry Andric AsanThreadContext *GetThreadContextByTidLocked(u32 tid) { 9268d75effSDimitry Andric return static_cast<AsanThreadContext *>( 9368d75effSDimitry Andric asanThreadRegistry().GetThreadLocked(tid)); 9468d75effSDimitry Andric } 9568d75effSDimitry Andric 9668d75effSDimitry Andric // AsanThread implementation. 9768d75effSDimitry Andric 985f757f3fSDimitry Andric AsanThread *AsanThread::Create(const void *start_data, uptr data_size, 9968d75effSDimitry Andric u32 parent_tid, StackTrace *stack, 10068d75effSDimitry Andric bool detached) { 10168d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 10268d75effSDimitry Andric uptr size = RoundUpTo(sizeof(AsanThread), PageSize); 10368d75effSDimitry Andric AsanThread *thread = (AsanThread *)MmapOrDie(size, __func__); 1045f757f3fSDimitry Andric if (data_size) { 1055f757f3fSDimitry Andric uptr availible_size = (uptr)thread + size - (uptr)(thread->start_data_); 1065f757f3fSDimitry Andric CHECK_LE(data_size, availible_size); 1075f757f3fSDimitry Andric internal_memcpy(thread->start_data_, start_data, data_size); 1085f757f3fSDimitry Andric } 10968d75effSDimitry Andric AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; 110349cc55cSDimitry Andric asanThreadRegistry().CreateThread(0, detached, parent_tid, &args); 11168d75effSDimitry Andric 11268d75effSDimitry Andric return thread; 11368d75effSDimitry Andric } 11468d75effSDimitry Andric 1155f757f3fSDimitry Andric void AsanThread::GetStartData(void *out, uptr out_size) const { 1165f757f3fSDimitry Andric internal_memcpy(out, start_data_, out_size); 1175f757f3fSDimitry Andric } 1185f757f3fSDimitry Andric 11968d75effSDimitry Andric void AsanThread::TSDDtor(void *tsd) { 12068d75effSDimitry Andric AsanThreadContext *context = (AsanThreadContext *)tsd; 12168d75effSDimitry Andric VReport(1, "T%d TSDDtor\n", context->tid); 12268d75effSDimitry Andric if (context->thread) 12368d75effSDimitry Andric context->thread->Destroy(); 12468d75effSDimitry Andric } 12568d75effSDimitry Andric 12668d75effSDimitry Andric void AsanThread::Destroy() { 12768d75effSDimitry Andric int tid = this->tid(); 12868d75effSDimitry Andric VReport(1, "T%d exited\n", tid); 12968d75effSDimitry Andric 130fe6060f1SDimitry Andric bool was_running = 131fe6060f1SDimitry Andric (asanThreadRegistry().FinishThread(tid) == ThreadStatusRunning); 132fe6060f1SDimitry Andric if (was_running) { 133fe6060f1SDimitry Andric if (AsanThread *thread = GetCurrentThread()) 134fe6060f1SDimitry Andric CHECK_EQ(this, thread); 13568d75effSDimitry Andric malloc_storage().CommitBack(); 136fe6060f1SDimitry Andric if (common_flags()->use_sigaltstack) 137fe6060f1SDimitry Andric UnsetAlternateSignalStack(); 13868d75effSDimitry Andric FlushToDeadThreadStats(&stats_); 13968d75effSDimitry Andric // We also clear the shadow on thread destruction because 14068d75effSDimitry Andric // some code may still be executing in later TSD destructors 14168d75effSDimitry Andric // and we don't want it to have any poisoned stack. 14268d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 14368d75effSDimitry Andric DeleteFakeStack(tid); 144fe6060f1SDimitry Andric } else { 145fe6060f1SDimitry Andric CHECK_NE(this, GetCurrentThread()); 146fe6060f1SDimitry Andric } 14768d75effSDimitry Andric uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached()); 14868d75effSDimitry Andric UnmapOrDie(this, size); 149fe6060f1SDimitry Andric if (was_running) 15068d75effSDimitry Andric DTLS_Destroy(); 15168d75effSDimitry Andric } 15268d75effSDimitry Andric 15368d75effSDimitry Andric void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, 15468d75effSDimitry Andric uptr size) { 15568d75effSDimitry Andric if (atomic_load(&stack_switching_, memory_order_relaxed)) { 15668d75effSDimitry Andric Report("ERROR: starting fiber switch while in fiber switch\n"); 15768d75effSDimitry Andric Die(); 15868d75effSDimitry Andric } 15968d75effSDimitry Andric 16068d75effSDimitry Andric next_stack_bottom_ = bottom; 16168d75effSDimitry Andric next_stack_top_ = bottom + size; 16268d75effSDimitry Andric atomic_store(&stack_switching_, 1, memory_order_release); 16368d75effSDimitry Andric 16468d75effSDimitry Andric FakeStack *current_fake_stack = fake_stack_; 16568d75effSDimitry Andric if (fake_stack_save) 16668d75effSDimitry Andric *fake_stack_save = fake_stack_; 16768d75effSDimitry Andric fake_stack_ = nullptr; 16868d75effSDimitry Andric SetTLSFakeStack(nullptr); 16968d75effSDimitry Andric // if fake_stack_save is null, the fiber will die, delete the fakestack 17068d75effSDimitry Andric if (!fake_stack_save && current_fake_stack) 17168d75effSDimitry Andric current_fake_stack->Destroy(this->tid()); 17268d75effSDimitry Andric } 17368d75effSDimitry Andric 17406c3fb27SDimitry Andric void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old, 17568d75effSDimitry Andric uptr *size_old) { 17668d75effSDimitry Andric if (!atomic_load(&stack_switching_, memory_order_relaxed)) { 17768d75effSDimitry Andric Report("ERROR: finishing a fiber switch that has not started\n"); 17868d75effSDimitry Andric Die(); 17968d75effSDimitry Andric } 18068d75effSDimitry Andric 18168d75effSDimitry Andric if (fake_stack_save) { 18268d75effSDimitry Andric SetTLSFakeStack(fake_stack_save); 18368d75effSDimitry Andric fake_stack_ = fake_stack_save; 18468d75effSDimitry Andric } 18568d75effSDimitry Andric 18668d75effSDimitry Andric if (bottom_old) 18768d75effSDimitry Andric *bottom_old = stack_bottom_; 18868d75effSDimitry Andric if (size_old) 18968d75effSDimitry Andric *size_old = stack_top_ - stack_bottom_; 19068d75effSDimitry Andric stack_bottom_ = next_stack_bottom_; 19168d75effSDimitry Andric stack_top_ = next_stack_top_; 19268d75effSDimitry Andric atomic_store(&stack_switching_, 0, memory_order_release); 19368d75effSDimitry Andric next_stack_top_ = 0; 19468d75effSDimitry Andric next_stack_bottom_ = 0; 19568d75effSDimitry Andric } 19668d75effSDimitry Andric 19768d75effSDimitry Andric inline AsanThread::StackBounds AsanThread::GetStackBounds() const { 19868d75effSDimitry Andric if (!atomic_load(&stack_switching_, memory_order_acquire)) { 19968d75effSDimitry Andric // Make sure the stack bounds are fully initialized. 20006c3fb27SDimitry Andric if (stack_bottom_ >= stack_top_) 20106c3fb27SDimitry Andric return {0, 0}; 20268d75effSDimitry Andric return {stack_bottom_, stack_top_}; 20368d75effSDimitry Andric } 20468d75effSDimitry Andric char local; 20568d75effSDimitry Andric const uptr cur_stack = (uptr)&local; 20668d75effSDimitry Andric // Note: need to check next stack first, because FinishSwitchFiber 20768d75effSDimitry Andric // may be in process of overwriting stack_top_/bottom_. But in such case 20868d75effSDimitry Andric // we are already on the next stack. 20968d75effSDimitry Andric if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_) 21068d75effSDimitry Andric return {next_stack_bottom_, next_stack_top_}; 21168d75effSDimitry Andric return {stack_bottom_, stack_top_}; 21268d75effSDimitry Andric } 21368d75effSDimitry Andric 21406c3fb27SDimitry Andric uptr AsanThread::stack_top() { return GetStackBounds().top; } 21568d75effSDimitry Andric 21606c3fb27SDimitry Andric uptr AsanThread::stack_bottom() { return GetStackBounds().bottom; } 21768d75effSDimitry Andric 21868d75effSDimitry Andric uptr AsanThread::stack_size() { 21968d75effSDimitry Andric const auto bounds = GetStackBounds(); 22068d75effSDimitry Andric return bounds.top - bounds.bottom; 22168d75effSDimitry Andric } 22268d75effSDimitry Andric 223e8d8bef9SDimitry Andric // We want to create the FakeStack lazily on the first use, but not earlier 22468d75effSDimitry Andric // than the stack size is known and the procedure has to be async-signal safe. 22568d75effSDimitry Andric FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { 22668d75effSDimitry Andric uptr stack_size = this->stack_size(); 22768d75effSDimitry Andric if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. 22868d75effSDimitry Andric return nullptr; 22968d75effSDimitry Andric uptr old_val = 0; 23068d75effSDimitry Andric // fake_stack_ has 3 states: 23168d75effSDimitry Andric // 0 -- not initialized 23268d75effSDimitry Andric // 1 -- being initialized 23368d75effSDimitry Andric // ptr -- initialized 23468d75effSDimitry Andric // This CAS checks if the state was 0 and if so changes it to state 1, 23568d75effSDimitry Andric // if that was successful, it initializes the pointer. 23668d75effSDimitry Andric if (atomic_compare_exchange_strong( 23768d75effSDimitry Andric reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL, 23868d75effSDimitry Andric memory_order_relaxed)) { 23968d75effSDimitry Andric uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size)); 24068d75effSDimitry Andric CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log); 24168d75effSDimitry Andric stack_size_log = 24268d75effSDimitry Andric Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log)); 24368d75effSDimitry Andric stack_size_log = 24468d75effSDimitry Andric Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log)); 24568d75effSDimitry Andric fake_stack_ = FakeStack::Create(stack_size_log); 246e8d8bef9SDimitry Andric DCHECK_EQ(GetCurrentThread(), this); 24768d75effSDimitry Andric SetTLSFakeStack(fake_stack_); 24868d75effSDimitry Andric return fake_stack_; 24968d75effSDimitry Andric } 25068d75effSDimitry Andric return nullptr; 25168d75effSDimitry Andric } 25268d75effSDimitry Andric 25368d75effSDimitry Andric void AsanThread::Init(const InitOptions *options) { 254fe6060f1SDimitry Andric DCHECK_NE(tid(), kInvalidTid); 25568d75effSDimitry Andric next_stack_top_ = next_stack_bottom_ = 0; 25668d75effSDimitry Andric atomic_store(&stack_switching_, false, memory_order_release); 25768d75effSDimitry Andric CHECK_EQ(this->stack_size(), 0U); 25868d75effSDimitry Andric SetThreadStackAndTls(options); 25968d75effSDimitry Andric if (stack_top_ != stack_bottom_) { 26068d75effSDimitry Andric CHECK_GT(this->stack_size(), 0U); 26168d75effSDimitry Andric CHECK(AddrIsInMem(stack_bottom_)); 26268d75effSDimitry Andric CHECK(AddrIsInMem(stack_top_ - 1)); 26368d75effSDimitry Andric } 26468d75effSDimitry Andric ClearShadowForThreadStackAndTLS(); 26568d75effSDimitry Andric fake_stack_ = nullptr; 266e8d8bef9SDimitry Andric if (__asan_option_detect_stack_use_after_return && 267e8d8bef9SDimitry Andric tid() == GetCurrentTidOrInvalid()) { 268e8d8bef9SDimitry Andric // AsyncSignalSafeLazyInitFakeStack makes use of threadlocals and must be 269e8d8bef9SDimitry Andric // called from the context of the thread it is initializing, not its parent. 270e8d8bef9SDimitry Andric // Most platforms call AsanThread::Init on the newly-spawned thread, but 271e8d8bef9SDimitry Andric // Fuchsia calls this function from the parent thread. To support that 272e8d8bef9SDimitry Andric // approach, we avoid calling AsyncSignalSafeLazyInitFakeStack here; it will 273e8d8bef9SDimitry Andric // be called by the new thread when it first attempts to access the fake 274e8d8bef9SDimitry Andric // stack. 27568d75effSDimitry Andric AsyncSignalSafeLazyInitFakeStack(); 276e8d8bef9SDimitry Andric } 27768d75effSDimitry Andric int local = 0; 27868d75effSDimitry Andric VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), 27968d75effSDimitry Andric (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_, 280349cc55cSDimitry Andric (void *)&local); 28168d75effSDimitry Andric } 28268d75effSDimitry Andric 283fe6060f1SDimitry Andric // Fuchsia doesn't use ThreadStart. 284fe6060f1SDimitry Andric // asan_fuchsia.c definies CreateMainThread and SetThreadStackAndTls. 285fe6060f1SDimitry Andric #if !SANITIZER_FUCHSIA 28668d75effSDimitry Andric 2875f757f3fSDimitry Andric void AsanThread::ThreadStart(tid_t os_id) { 28868d75effSDimitry Andric Init(); 28968d75effSDimitry Andric asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr); 29068d75effSDimitry Andric 29106c3fb27SDimitry Andric if (common_flags()->use_sigaltstack) 29206c3fb27SDimitry Andric SetAlternateSignalStack(); 29368d75effSDimitry Andric } 29468d75effSDimitry Andric 29568d75effSDimitry Andric AsanThread *CreateMainThread() { 29668d75effSDimitry Andric AsanThread *main_thread = AsanThread::Create( 2975f757f3fSDimitry Andric /* parent_tid */ kMainTid, 29868d75effSDimitry Andric /* stack */ nullptr, /* detached */ true); 29968d75effSDimitry Andric SetCurrentThread(main_thread); 300e8d8bef9SDimitry Andric main_thread->ThreadStart(internal_getpid()); 30168d75effSDimitry Andric return main_thread; 30268d75effSDimitry Andric } 30368d75effSDimitry Andric 30468d75effSDimitry Andric // This implementation doesn't use the argument, which is just passed down 30568d75effSDimitry Andric // from the caller of Init (which see, above). It's only there to support 30668d75effSDimitry Andric // OS-specific implementations that need more information passed through. 30768d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const InitOptions *options) { 30868d75effSDimitry Andric DCHECK_EQ(options, nullptr); 30968d75effSDimitry Andric uptr tls_size = 0; 31068d75effSDimitry Andric uptr stack_size = 0; 311fe6060f1SDimitry Andric GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size, 312fe6060f1SDimitry Andric &tls_begin_, &tls_size); 3130eae32dcSDimitry Andric stack_top_ = RoundDownTo(stack_bottom_ + stack_size, ASAN_SHADOW_GRANULARITY); 31406c3fb27SDimitry Andric stack_bottom_ = RoundDownTo(stack_bottom_, ASAN_SHADOW_GRANULARITY); 31568d75effSDimitry Andric tls_end_ = tls_begin_ + tls_size; 31668d75effSDimitry Andric dtls_ = DTLS_Get(); 31768d75effSDimitry Andric 31868d75effSDimitry Andric if (stack_top_ != stack_bottom_) { 31968d75effSDimitry Andric int local; 32068d75effSDimitry Andric CHECK(AddrIsInStack((uptr)&local)); 32168d75effSDimitry Andric } 32268d75effSDimitry Andric } 32368d75effSDimitry Andric 324fe6060f1SDimitry Andric #endif // !SANITIZER_FUCHSIA 32568d75effSDimitry Andric 32668d75effSDimitry Andric void AsanThread::ClearShadowForThreadStackAndTLS() { 32768d75effSDimitry Andric if (stack_top_ != stack_bottom_) 32868d75effSDimitry Andric PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); 32968d75effSDimitry Andric if (tls_begin_ != tls_end_) { 3300eae32dcSDimitry Andric uptr tls_begin_aligned = RoundDownTo(tls_begin_, ASAN_SHADOW_GRANULARITY); 3310eae32dcSDimitry Andric uptr tls_end_aligned = RoundUpTo(tls_end_, ASAN_SHADOW_GRANULARITY); 33281ad6265SDimitry Andric FastPoisonShadow(tls_begin_aligned, tls_end_aligned - tls_begin_aligned, 0); 33368d75effSDimitry Andric } 33468d75effSDimitry Andric } 33568d75effSDimitry Andric 33668d75effSDimitry Andric bool AsanThread::GetStackFrameAccessByAddr(uptr addr, 33768d75effSDimitry Andric StackFrameAccess *access) { 33868d75effSDimitry Andric if (stack_top_ == stack_bottom_) 33968d75effSDimitry Andric return false; 34068d75effSDimitry Andric 34168d75effSDimitry Andric uptr bottom = 0; 34268d75effSDimitry Andric if (AddrIsInStack(addr)) { 34368d75effSDimitry Andric bottom = stack_bottom(); 344fe6060f1SDimitry Andric } else if (FakeStack *fake_stack = get_fake_stack()) { 345fe6060f1SDimitry Andric bottom = fake_stack->AddrIsInFakeStack(addr); 34668d75effSDimitry Andric CHECK(bottom); 34768d75effSDimitry Andric access->offset = addr - bottom; 34868d75effSDimitry Andric access->frame_pc = ((uptr *)bottom)[2]; 34968d75effSDimitry Andric access->frame_descr = (const char *)((uptr *)bottom)[1]; 35068d75effSDimitry Andric return true; 35168d75effSDimitry Andric } 35268d75effSDimitry Andric uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr. 3530eae32dcSDimitry Andric uptr mem_ptr = RoundDownTo(aligned_addr, ASAN_SHADOW_GRANULARITY); 35468d75effSDimitry Andric u8 *shadow_ptr = (u8 *)MemToShadow(aligned_addr); 35568d75effSDimitry Andric u8 *shadow_bottom = (u8 *)MemToShadow(bottom); 35668d75effSDimitry Andric 35768d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 35868d75effSDimitry Andric *shadow_ptr != kAsanStackLeftRedzoneMagic) { 35968d75effSDimitry Andric shadow_ptr--; 3600eae32dcSDimitry Andric mem_ptr -= ASAN_SHADOW_GRANULARITY; 36168d75effSDimitry Andric } 36268d75effSDimitry Andric 36368d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 36468d75effSDimitry Andric *shadow_ptr == kAsanStackLeftRedzoneMagic) { 36568d75effSDimitry Andric shadow_ptr--; 3660eae32dcSDimitry Andric mem_ptr -= ASAN_SHADOW_GRANULARITY; 36768d75effSDimitry Andric } 36868d75effSDimitry Andric 36968d75effSDimitry Andric if (shadow_ptr < shadow_bottom) { 37068d75effSDimitry Andric return false; 37168d75effSDimitry Andric } 37268d75effSDimitry Andric 3730eae32dcSDimitry Andric uptr *ptr = (uptr *)(mem_ptr + ASAN_SHADOW_GRANULARITY); 37468d75effSDimitry Andric CHECK(ptr[0] == kCurrentStackFrameMagic); 37568d75effSDimitry Andric access->offset = addr - (uptr)ptr; 37668d75effSDimitry Andric access->frame_pc = ptr[2]; 37768d75effSDimitry Andric access->frame_descr = (const char *)ptr[1]; 37868d75effSDimitry Andric return true; 37968d75effSDimitry Andric } 38068d75effSDimitry Andric 38168d75effSDimitry Andric uptr AsanThread::GetStackVariableShadowStart(uptr addr) { 38268d75effSDimitry Andric uptr bottom = 0; 38368d75effSDimitry Andric if (AddrIsInStack(addr)) { 38468d75effSDimitry Andric bottom = stack_bottom(); 385fe6060f1SDimitry Andric } else if (FakeStack *fake_stack = get_fake_stack()) { 386fe6060f1SDimitry Andric bottom = fake_stack->AddrIsInFakeStack(addr); 387e8d8bef9SDimitry Andric if (bottom == 0) { 388e8d8bef9SDimitry Andric return 0; 389e8d8bef9SDimitry Andric } 39068d75effSDimitry Andric } else { 39168d75effSDimitry Andric return 0; 39268d75effSDimitry Andric } 39368d75effSDimitry Andric 39468d75effSDimitry Andric uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr. 39568d75effSDimitry Andric u8 *shadow_ptr = (u8 *)MemToShadow(aligned_addr); 39668d75effSDimitry Andric u8 *shadow_bottom = (u8 *)MemToShadow(bottom); 39768d75effSDimitry Andric 39868d75effSDimitry Andric while (shadow_ptr >= shadow_bottom && 39968d75effSDimitry Andric (*shadow_ptr != kAsanStackLeftRedzoneMagic && 40068d75effSDimitry Andric *shadow_ptr != kAsanStackMidRedzoneMagic && 40168d75effSDimitry Andric *shadow_ptr != kAsanStackRightRedzoneMagic)) 40268d75effSDimitry Andric shadow_ptr--; 40368d75effSDimitry Andric 40468d75effSDimitry Andric return (uptr)shadow_ptr + 1; 40568d75effSDimitry Andric } 40668d75effSDimitry Andric 40768d75effSDimitry Andric bool AsanThread::AddrIsInStack(uptr addr) { 40868d75effSDimitry Andric const auto bounds = GetStackBounds(); 40968d75effSDimitry Andric return addr >= bounds.bottom && addr < bounds.top; 41068d75effSDimitry Andric } 41168d75effSDimitry Andric 41268d75effSDimitry Andric static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, 41368d75effSDimitry Andric void *addr) { 41468d75effSDimitry Andric AsanThreadContext *tctx = static_cast<AsanThreadContext *>(tctx_base); 41568d75effSDimitry Andric AsanThread *t = tctx->thread; 416fe6060f1SDimitry Andric if (!t) 41768d75effSDimitry Andric return false; 418fe6060f1SDimitry Andric if (t->AddrIsInStack((uptr)addr)) 419fe6060f1SDimitry Andric return true; 420fe6060f1SDimitry Andric FakeStack *fake_stack = t->get_fake_stack(); 421fe6060f1SDimitry Andric if (!fake_stack) 422fe6060f1SDimitry Andric return false; 423fe6060f1SDimitry Andric return fake_stack->AddrIsInFakeStack((uptr)addr); 42468d75effSDimitry Andric } 42568d75effSDimitry Andric 42668d75effSDimitry Andric AsanThread *GetCurrentThread() { 42768d75effSDimitry Andric AsanThreadContext *context = 42868d75effSDimitry Andric reinterpret_cast<AsanThreadContext *>(AsanTSDGet()); 42968d75effSDimitry Andric if (!context) { 43068d75effSDimitry Andric if (SANITIZER_ANDROID) { 43168d75effSDimitry Andric // On Android, libc constructor is called _after_ asan_init, and cleans up 43268d75effSDimitry Andric // TSD. Try to figure out if this is still the main thread by the stack 43368d75effSDimitry Andric // address. We are not entirely sure that we have correct main thread 43468d75effSDimitry Andric // limits, so only do this magic on Android, and only if the found thread 43568d75effSDimitry Andric // is the main thread. 436fe6060f1SDimitry Andric AsanThreadContext *tctx = GetThreadContextByTidLocked(kMainTid); 43768d75effSDimitry Andric if (tctx && ThreadStackContainsAddress(tctx, &context)) { 43868d75effSDimitry Andric SetCurrentThread(tctx->thread); 43968d75effSDimitry Andric return tctx->thread; 44068d75effSDimitry Andric } 44168d75effSDimitry Andric } 44268d75effSDimitry Andric return nullptr; 44368d75effSDimitry Andric } 44468d75effSDimitry Andric return context->thread; 44568d75effSDimitry Andric } 44668d75effSDimitry Andric 44768d75effSDimitry Andric void SetCurrentThread(AsanThread *t) { 44868d75effSDimitry Andric CHECK(t->context()); 449349cc55cSDimitry Andric VReport(2, "SetCurrentThread: %p for thread %p\n", (void *)t->context(), 45068d75effSDimitry Andric (void *)GetThreadSelf()); 45168d75effSDimitry Andric // Make sure we do not reset the current AsanThread. 45268d75effSDimitry Andric CHECK_EQ(0, AsanTSDGet()); 45368d75effSDimitry Andric AsanTSDSet(t->context()); 45468d75effSDimitry Andric CHECK_EQ(t->context(), AsanTSDGet()); 45568d75effSDimitry Andric } 45668d75effSDimitry Andric 45768d75effSDimitry Andric u32 GetCurrentTidOrInvalid() { 45868d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 45968d75effSDimitry Andric return t ? t->tid() : kInvalidTid; 46068d75effSDimitry Andric } 46168d75effSDimitry Andric 46268d75effSDimitry Andric AsanThread *FindThreadByStackAddress(uptr addr) { 46368d75effSDimitry Andric asanThreadRegistry().CheckLocked(); 46468d75effSDimitry Andric AsanThreadContext *tctx = static_cast<AsanThreadContext *>( 46568d75effSDimitry Andric asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress, 46668d75effSDimitry Andric (void *)addr)); 46768d75effSDimitry Andric return tctx ? tctx->thread : nullptr; 46868d75effSDimitry Andric } 46968d75effSDimitry Andric 47068d75effSDimitry Andric void EnsureMainThreadIDIsCorrect() { 47168d75effSDimitry Andric AsanThreadContext *context = 47268d75effSDimitry Andric reinterpret_cast<AsanThreadContext *>(AsanTSDGet()); 473fe6060f1SDimitry Andric if (context && (context->tid == kMainTid)) 47468d75effSDimitry Andric context->os_id = GetTid(); 47568d75effSDimitry Andric } 47668d75effSDimitry Andric 47768d75effSDimitry Andric __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) { 47868d75effSDimitry Andric __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( 47968d75effSDimitry Andric __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); 48006c3fb27SDimitry Andric if (!context) 48106c3fb27SDimitry Andric return nullptr; 48268d75effSDimitry Andric return context->thread; 48368d75effSDimitry Andric } 48468d75effSDimitry Andric } // namespace __asan 48568d75effSDimitry Andric 48668d75effSDimitry Andric // --- Implementation of LSan-specific functions --- {{{1 48768d75effSDimitry Andric namespace __lsan { 48806c3fb27SDimitry Andric void LockThreads() { 48906c3fb27SDimitry Andric __asan::asanThreadRegistry().Lock(); 49006c3fb27SDimitry Andric __asan::asanThreadArgRetval().Lock(); 49106c3fb27SDimitry Andric } 492bdd1243dSDimitry Andric 49306c3fb27SDimitry Andric void UnlockThreads() { 49406c3fb27SDimitry Andric __asan::asanThreadArgRetval().Unlock(); 49506c3fb27SDimitry Andric __asan::asanThreadRegistry().Unlock(); 49606c3fb27SDimitry Andric } 497bdd1243dSDimitry Andric 498bdd1243dSDimitry Andric static ThreadRegistry *GetAsanThreadRegistryLocked() { 499bdd1243dSDimitry Andric __asan::asanThreadRegistry().CheckLocked(); 500bdd1243dSDimitry Andric return &__asan::asanThreadRegistry(); 501bdd1243dSDimitry Andric } 502bdd1243dSDimitry Andric 503bdd1243dSDimitry Andric void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); } 504bdd1243dSDimitry Andric 50568d75effSDimitry Andric bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, 50668d75effSDimitry Andric uptr *tls_begin, uptr *tls_end, uptr *cache_begin, 50768d75effSDimitry Andric uptr *cache_end, DTLS **dtls) { 50868d75effSDimitry Andric __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); 50906c3fb27SDimitry Andric if (!t) 51006c3fb27SDimitry Andric return false; 51168d75effSDimitry Andric *stack_begin = t->stack_bottom(); 51268d75effSDimitry Andric *stack_end = t->stack_top(); 51368d75effSDimitry Andric *tls_begin = t->tls_begin(); 51468d75effSDimitry Andric *tls_end = t->tls_end(); 51568d75effSDimitry Andric // ASan doesn't keep allocator caches in TLS, so these are unused. 51668d75effSDimitry Andric *cache_begin = 0; 51768d75effSDimitry Andric *cache_end = 0; 51868d75effSDimitry Andric *dtls = t->dtls(); 51968d75effSDimitry Andric return true; 52068d75effSDimitry Andric } 52168d75effSDimitry Andric 5225ffd83dbSDimitry Andric void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {} 5235ffd83dbSDimitry Andric 524bdd1243dSDimitry Andric void GetThreadExtraStackRangesLocked(tid_t os_id, 525bdd1243dSDimitry Andric InternalMmapVector<Range> *ranges) { 52668d75effSDimitry Andric __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); 527fe6060f1SDimitry Andric if (!t) 528fe6060f1SDimitry Andric return; 529fe6060f1SDimitry Andric __asan::FakeStack *fake_stack = t->get_fake_stack(); 530fe6060f1SDimitry Andric if (!fake_stack) 531fe6060f1SDimitry Andric return; 532bdd1243dSDimitry Andric 533bdd1243dSDimitry Andric fake_stack->ForEachFakeFrame( 534bdd1243dSDimitry Andric [](uptr begin, uptr end, void *arg) { 535bdd1243dSDimitry Andric reinterpret_cast<InternalMmapVector<Range> *>(arg)->push_back( 536bdd1243dSDimitry Andric {begin, end}); 537bdd1243dSDimitry Andric }, 538bdd1243dSDimitry Andric ranges); 53968d75effSDimitry Andric } 54068d75effSDimitry Andric 541bdd1243dSDimitry Andric void GetThreadExtraStackRangesLocked(InternalMmapVector<Range> *ranges) { 542bdd1243dSDimitry Andric GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked( 543bdd1243dSDimitry Andric [](ThreadContextBase *tctx, void *arg) { 544bdd1243dSDimitry Andric GetThreadExtraStackRangesLocked( 545bdd1243dSDimitry Andric tctx->os_id, reinterpret_cast<InternalMmapVector<Range> *>(arg)); 546bdd1243dSDimitry Andric }, 547bdd1243dSDimitry Andric ranges); 54868d75effSDimitry Andric } 54968d75effSDimitry Andric 550bdd1243dSDimitry Andric void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) { 55106c3fb27SDimitry Andric __asan::asanThreadArgRetval().GetAllPtrsLocked(ptrs); 55268d75effSDimitry Andric } 55368d75effSDimitry Andric 554bdd1243dSDimitry Andric void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) { 555bdd1243dSDimitry Andric GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked( 556bdd1243dSDimitry Andric [](ThreadContextBase *tctx, void *threads) { 557bdd1243dSDimitry Andric if (tctx->status == ThreadStatusRunning) 558bdd1243dSDimitry Andric reinterpret_cast<InternalMmapVector<tid_t> *>(threads)->push_back( 559bdd1243dSDimitry Andric tctx->os_id); 560bdd1243dSDimitry Andric }, 561bdd1243dSDimitry Andric threads); 56268d75effSDimitry Andric } 56368d75effSDimitry Andric 56468d75effSDimitry Andric } // namespace __lsan 56568d75effSDimitry Andric 56668d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1 56768d75effSDimitry Andric using namespace __asan; 56868d75effSDimitry Andric 56968d75effSDimitry Andric extern "C" { 57068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 57168d75effSDimitry Andric void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom, 57268d75effSDimitry Andric uptr size) { 57368d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 57468d75effSDimitry Andric if (!t) { 57568d75effSDimitry Andric VReport(1, "__asan_start_switch_fiber called from unknown thread\n"); 57668d75effSDimitry Andric return; 57768d75effSDimitry Andric } 57868d75effSDimitry Andric t->StartSwitchFiber((FakeStack **)fakestacksave, (uptr)bottom, size); 57968d75effSDimitry Andric } 58068d75effSDimitry Andric 58168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 58206c3fb27SDimitry Andric void __sanitizer_finish_switch_fiber(void *fakestack, const void **bottom_old, 58368d75effSDimitry Andric uptr *size_old) { 58468d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 58568d75effSDimitry Andric if (!t) { 58668d75effSDimitry Andric VReport(1, "__asan_finish_switch_fiber called from unknown thread\n"); 58768d75effSDimitry Andric return; 58868d75effSDimitry Andric } 58906c3fb27SDimitry Andric t->FinishSwitchFiber((FakeStack *)fakestack, (uptr *)bottom_old, 59068d75effSDimitry Andric (uptr *)size_old); 59168d75effSDimitry Andric } 59268d75effSDimitry Andric } 593