13cab2bb3Spatrick //===-- asan_thread.cpp ---------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of AddressSanitizer, an address sanity checker.
103cab2bb3Spatrick //
113cab2bb3Spatrick // Thread-related code.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick #include "asan_allocator.h"
143cab2bb3Spatrick #include "asan_interceptors.h"
153cab2bb3Spatrick #include "asan_poisoning.h"
163cab2bb3Spatrick #include "asan_stack.h"
173cab2bb3Spatrick #include "asan_thread.h"
183cab2bb3Spatrick #include "asan_mapping.h"
193cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
203cab2bb3Spatrick #include "sanitizer_common/sanitizer_placement_new.h"
213cab2bb3Spatrick #include "sanitizer_common/sanitizer_stackdepot.h"
223cab2bb3Spatrick #include "sanitizer_common/sanitizer_tls_get_addr.h"
233cab2bb3Spatrick #include "lsan/lsan_common.h"
243cab2bb3Spatrick
253cab2bb3Spatrick namespace __asan {
263cab2bb3Spatrick
273cab2bb3Spatrick // AsanThreadContext implementation.
283cab2bb3Spatrick
OnCreated(void * arg)293cab2bb3Spatrick void AsanThreadContext::OnCreated(void *arg) {
303cab2bb3Spatrick CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
313cab2bb3Spatrick if (args->stack)
323cab2bb3Spatrick stack_id = StackDepotPut(*args->stack);
333cab2bb3Spatrick thread = args->thread;
343cab2bb3Spatrick thread->set_context(this);
353cab2bb3Spatrick }
363cab2bb3Spatrick
OnFinished()373cab2bb3Spatrick void AsanThreadContext::OnFinished() {
383cab2bb3Spatrick // Drop the link to the AsanThread object.
393cab2bb3Spatrick thread = nullptr;
403cab2bb3Spatrick }
413cab2bb3Spatrick
423cab2bb3Spatrick // MIPS requires aligned address
433cab2bb3Spatrick static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
443cab2bb3Spatrick static ThreadRegistry *asan_thread_registry;
453cab2bb3Spatrick
46*810390e3Srobert static Mutex mu_for_thread_context;
473cab2bb3Spatrick static LowLevelAllocator allocator_for_thread_context;
483cab2bb3Spatrick
GetAsanThreadContext(u32 tid)493cab2bb3Spatrick static ThreadContextBase *GetAsanThreadContext(u32 tid) {
50*810390e3Srobert Lock lock(&mu_for_thread_context);
513cab2bb3Spatrick return new(allocator_for_thread_context) AsanThreadContext(tid);
523cab2bb3Spatrick }
533cab2bb3Spatrick
asanThreadRegistry()543cab2bb3Spatrick ThreadRegistry &asanThreadRegistry() {
553cab2bb3Spatrick static bool initialized;
563cab2bb3Spatrick // Don't worry about thread_safety - this should be called when there is
573cab2bb3Spatrick // a single thread.
583cab2bb3Spatrick if (!initialized) {
593cab2bb3Spatrick // Never reuse ASan threads: we store pointer to AsanThreadContext
603cab2bb3Spatrick // in TSD and can't reliably tell when no more TSD destructors will
613cab2bb3Spatrick // be called. It would be wrong to reuse AsanThreadContext for another
623cab2bb3Spatrick // thread before all TSD destructors will be called for it.
63d89ec533Spatrick asan_thread_registry =
64d89ec533Spatrick new (thread_registry_placeholder) ThreadRegistry(GetAsanThreadContext);
653cab2bb3Spatrick initialized = true;
663cab2bb3Spatrick }
673cab2bb3Spatrick return *asan_thread_registry;
683cab2bb3Spatrick }
693cab2bb3Spatrick
GetThreadContextByTidLocked(u32 tid)703cab2bb3Spatrick AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
713cab2bb3Spatrick return static_cast<AsanThreadContext *>(
723cab2bb3Spatrick asanThreadRegistry().GetThreadLocked(tid));
733cab2bb3Spatrick }
743cab2bb3Spatrick
753cab2bb3Spatrick // AsanThread implementation.
763cab2bb3Spatrick
Create(thread_callback_t start_routine,void * arg,u32 parent_tid,StackTrace * stack,bool detached)773cab2bb3Spatrick AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
783cab2bb3Spatrick u32 parent_tid, StackTrace *stack,
793cab2bb3Spatrick bool detached) {
803cab2bb3Spatrick uptr PageSize = GetPageSizeCached();
813cab2bb3Spatrick uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
823cab2bb3Spatrick AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
833cab2bb3Spatrick thread->start_routine_ = start_routine;
843cab2bb3Spatrick thread->arg_ = arg;
853cab2bb3Spatrick AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
86*810390e3Srobert asanThreadRegistry().CreateThread(0, detached, parent_tid, &args);
873cab2bb3Spatrick
883cab2bb3Spatrick return thread;
893cab2bb3Spatrick }
903cab2bb3Spatrick
TSDDtor(void * tsd)913cab2bb3Spatrick void AsanThread::TSDDtor(void *tsd) {
923cab2bb3Spatrick AsanThreadContext *context = (AsanThreadContext*)tsd;
933cab2bb3Spatrick VReport(1, "T%d TSDDtor\n", context->tid);
943cab2bb3Spatrick if (context->thread)
953cab2bb3Spatrick context->thread->Destroy();
963cab2bb3Spatrick }
973cab2bb3Spatrick
Destroy()983cab2bb3Spatrick void AsanThread::Destroy() {
993cab2bb3Spatrick int tid = this->tid();
1003cab2bb3Spatrick VReport(1, "T%d exited\n", tid);
1013cab2bb3Spatrick
102d89ec533Spatrick bool was_running =
103d89ec533Spatrick (asanThreadRegistry().FinishThread(tid) == ThreadStatusRunning);
104d89ec533Spatrick if (was_running) {
105d89ec533Spatrick if (AsanThread *thread = GetCurrentThread())
106d89ec533Spatrick CHECK_EQ(this, thread);
1073cab2bb3Spatrick malloc_storage().CommitBack();
108d89ec533Spatrick if (common_flags()->use_sigaltstack)
109d89ec533Spatrick UnsetAlternateSignalStack();
1103cab2bb3Spatrick FlushToDeadThreadStats(&stats_);
1113cab2bb3Spatrick // We also clear the shadow on thread destruction because
1123cab2bb3Spatrick // some code may still be executing in later TSD destructors
1133cab2bb3Spatrick // and we don't want it to have any poisoned stack.
1143cab2bb3Spatrick ClearShadowForThreadStackAndTLS();
1153cab2bb3Spatrick DeleteFakeStack(tid);
116d89ec533Spatrick } else {
117d89ec533Spatrick CHECK_NE(this, GetCurrentThread());
118d89ec533Spatrick }
1193cab2bb3Spatrick uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
1203cab2bb3Spatrick UnmapOrDie(this, size);
121d89ec533Spatrick if (was_running)
1223cab2bb3Spatrick DTLS_Destroy();
1233cab2bb3Spatrick }
1243cab2bb3Spatrick
StartSwitchFiber(FakeStack ** fake_stack_save,uptr bottom,uptr size)1253cab2bb3Spatrick void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
1263cab2bb3Spatrick uptr size) {
1273cab2bb3Spatrick if (atomic_load(&stack_switching_, memory_order_relaxed)) {
1283cab2bb3Spatrick Report("ERROR: starting fiber switch while in fiber switch\n");
1293cab2bb3Spatrick Die();
1303cab2bb3Spatrick }
1313cab2bb3Spatrick
1323cab2bb3Spatrick next_stack_bottom_ = bottom;
1333cab2bb3Spatrick next_stack_top_ = bottom + size;
1343cab2bb3Spatrick atomic_store(&stack_switching_, 1, memory_order_release);
1353cab2bb3Spatrick
1363cab2bb3Spatrick FakeStack *current_fake_stack = fake_stack_;
1373cab2bb3Spatrick if (fake_stack_save)
1383cab2bb3Spatrick *fake_stack_save = fake_stack_;
1393cab2bb3Spatrick fake_stack_ = nullptr;
1403cab2bb3Spatrick SetTLSFakeStack(nullptr);
1413cab2bb3Spatrick // if fake_stack_save is null, the fiber will die, delete the fakestack
1423cab2bb3Spatrick if (!fake_stack_save && current_fake_stack)
1433cab2bb3Spatrick current_fake_stack->Destroy(this->tid());
1443cab2bb3Spatrick }
1453cab2bb3Spatrick
FinishSwitchFiber(FakeStack * fake_stack_save,uptr * bottom_old,uptr * size_old)1463cab2bb3Spatrick void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save,
1473cab2bb3Spatrick uptr *bottom_old,
1483cab2bb3Spatrick uptr *size_old) {
1493cab2bb3Spatrick if (!atomic_load(&stack_switching_, memory_order_relaxed)) {
1503cab2bb3Spatrick Report("ERROR: finishing a fiber switch that has not started\n");
1513cab2bb3Spatrick Die();
1523cab2bb3Spatrick }
1533cab2bb3Spatrick
1543cab2bb3Spatrick if (fake_stack_save) {
1553cab2bb3Spatrick SetTLSFakeStack(fake_stack_save);
1563cab2bb3Spatrick fake_stack_ = fake_stack_save;
1573cab2bb3Spatrick }
1583cab2bb3Spatrick
1593cab2bb3Spatrick if (bottom_old)
1603cab2bb3Spatrick *bottom_old = stack_bottom_;
1613cab2bb3Spatrick if (size_old)
1623cab2bb3Spatrick *size_old = stack_top_ - stack_bottom_;
1633cab2bb3Spatrick stack_bottom_ = next_stack_bottom_;
1643cab2bb3Spatrick stack_top_ = next_stack_top_;
1653cab2bb3Spatrick atomic_store(&stack_switching_, 0, memory_order_release);
1663cab2bb3Spatrick next_stack_top_ = 0;
1673cab2bb3Spatrick next_stack_bottom_ = 0;
1683cab2bb3Spatrick }
1693cab2bb3Spatrick
GetStackBounds() const1703cab2bb3Spatrick inline AsanThread::StackBounds AsanThread::GetStackBounds() const {
1713cab2bb3Spatrick if (!atomic_load(&stack_switching_, memory_order_acquire)) {
1723cab2bb3Spatrick // Make sure the stack bounds are fully initialized.
1733cab2bb3Spatrick if (stack_bottom_ >= stack_top_) return {0, 0};
1743cab2bb3Spatrick return {stack_bottom_, stack_top_};
1753cab2bb3Spatrick }
1763cab2bb3Spatrick char local;
1773cab2bb3Spatrick const uptr cur_stack = (uptr)&local;
1783cab2bb3Spatrick // Note: need to check next stack first, because FinishSwitchFiber
1793cab2bb3Spatrick // may be in process of overwriting stack_top_/bottom_. But in such case
1803cab2bb3Spatrick // we are already on the next stack.
1813cab2bb3Spatrick if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_)
1823cab2bb3Spatrick return {next_stack_bottom_, next_stack_top_};
1833cab2bb3Spatrick return {stack_bottom_, stack_top_};
1843cab2bb3Spatrick }
1853cab2bb3Spatrick
stack_top()1863cab2bb3Spatrick uptr AsanThread::stack_top() {
1873cab2bb3Spatrick return GetStackBounds().top;
1883cab2bb3Spatrick }
1893cab2bb3Spatrick
stack_bottom()1903cab2bb3Spatrick uptr AsanThread::stack_bottom() {
1913cab2bb3Spatrick return GetStackBounds().bottom;
1923cab2bb3Spatrick }
1933cab2bb3Spatrick
stack_size()1943cab2bb3Spatrick uptr AsanThread::stack_size() {
1953cab2bb3Spatrick const auto bounds = GetStackBounds();
1963cab2bb3Spatrick return bounds.top - bounds.bottom;
1973cab2bb3Spatrick }
1983cab2bb3Spatrick
199d89ec533Spatrick // We want to create the FakeStack lazily on the first use, but not earlier
2003cab2bb3Spatrick // than the stack size is known and the procedure has to be async-signal safe.
AsyncSignalSafeLazyInitFakeStack()2013cab2bb3Spatrick FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
2023cab2bb3Spatrick uptr stack_size = this->stack_size();
2033cab2bb3Spatrick if (stack_size == 0) // stack_size is not yet available, don't use FakeStack.
2043cab2bb3Spatrick return nullptr;
2053cab2bb3Spatrick uptr old_val = 0;
2063cab2bb3Spatrick // fake_stack_ has 3 states:
2073cab2bb3Spatrick // 0 -- not initialized
2083cab2bb3Spatrick // 1 -- being initialized
2093cab2bb3Spatrick // ptr -- initialized
2103cab2bb3Spatrick // This CAS checks if the state was 0 and if so changes it to state 1,
2113cab2bb3Spatrick // if that was successful, it initializes the pointer.
2123cab2bb3Spatrick if (atomic_compare_exchange_strong(
2133cab2bb3Spatrick reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL,
2143cab2bb3Spatrick memory_order_relaxed)) {
2153cab2bb3Spatrick uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size));
2163cab2bb3Spatrick CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
2173cab2bb3Spatrick stack_size_log =
2183cab2bb3Spatrick Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log));
2193cab2bb3Spatrick stack_size_log =
2203cab2bb3Spatrick Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
2213cab2bb3Spatrick fake_stack_ = FakeStack::Create(stack_size_log);
222d89ec533Spatrick DCHECK_EQ(GetCurrentThread(), this);
2233cab2bb3Spatrick SetTLSFakeStack(fake_stack_);
2243cab2bb3Spatrick return fake_stack_;
2253cab2bb3Spatrick }
2263cab2bb3Spatrick return nullptr;
2273cab2bb3Spatrick }
2283cab2bb3Spatrick
Init(const InitOptions * options)2293cab2bb3Spatrick void AsanThread::Init(const InitOptions *options) {
230d89ec533Spatrick DCHECK_NE(tid(), kInvalidTid);
2313cab2bb3Spatrick next_stack_top_ = next_stack_bottom_ = 0;
2323cab2bb3Spatrick atomic_store(&stack_switching_, false, memory_order_release);
2333cab2bb3Spatrick CHECK_EQ(this->stack_size(), 0U);
2343cab2bb3Spatrick SetThreadStackAndTls(options);
2353cab2bb3Spatrick if (stack_top_ != stack_bottom_) {
2363cab2bb3Spatrick CHECK_GT(this->stack_size(), 0U);
2373cab2bb3Spatrick CHECK(AddrIsInMem(stack_bottom_));
2383cab2bb3Spatrick CHECK(AddrIsInMem(stack_top_ - 1));
2393cab2bb3Spatrick }
2403cab2bb3Spatrick ClearShadowForThreadStackAndTLS();
2413cab2bb3Spatrick fake_stack_ = nullptr;
242d89ec533Spatrick if (__asan_option_detect_stack_use_after_return &&
243d89ec533Spatrick tid() == GetCurrentTidOrInvalid()) {
244d89ec533Spatrick // AsyncSignalSafeLazyInitFakeStack makes use of threadlocals and must be
245d89ec533Spatrick // called from the context of the thread it is initializing, not its parent.
246d89ec533Spatrick // Most platforms call AsanThread::Init on the newly-spawned thread, but
247d89ec533Spatrick // Fuchsia calls this function from the parent thread. To support that
248d89ec533Spatrick // approach, we avoid calling AsyncSignalSafeLazyInitFakeStack here; it will
249d89ec533Spatrick // be called by the new thread when it first attempts to access the fake
250d89ec533Spatrick // stack.
2513cab2bb3Spatrick AsyncSignalSafeLazyInitFakeStack();
252d89ec533Spatrick }
2533cab2bb3Spatrick int local = 0;
2543cab2bb3Spatrick VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
2553cab2bb3Spatrick (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
256*810390e3Srobert (void *)&local);
2573cab2bb3Spatrick }
2583cab2bb3Spatrick
259d89ec533Spatrick // Fuchsia doesn't use ThreadStart.
260d89ec533Spatrick // asan_fuchsia.c definies CreateMainThread and SetThreadStackAndTls.
261d89ec533Spatrick #if !SANITIZER_FUCHSIA
2623cab2bb3Spatrick
ThreadStart(tid_t os_id)263d89ec533Spatrick thread_return_t AsanThread::ThreadStart(tid_t os_id) {
2643cab2bb3Spatrick Init();
2653cab2bb3Spatrick asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
2663cab2bb3Spatrick
2673cab2bb3Spatrick if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
2683cab2bb3Spatrick
2693cab2bb3Spatrick if (!start_routine_) {
2703cab2bb3Spatrick // start_routine_ == 0 if we're on the main thread or on one of the
2713cab2bb3Spatrick // OS X libdispatch worker threads. But nobody is supposed to call
2723cab2bb3Spatrick // ThreadStart() for the worker threads.
2733cab2bb3Spatrick CHECK_EQ(tid(), 0);
2743cab2bb3Spatrick return 0;
2753cab2bb3Spatrick }
2763cab2bb3Spatrick
2773cab2bb3Spatrick thread_return_t res = start_routine_(arg_);
2783cab2bb3Spatrick
2793cab2bb3Spatrick // On POSIX systems we defer this to the TSD destructor. LSan will consider
2803cab2bb3Spatrick // the thread's memory as non-live from the moment we call Destroy(), even
2813cab2bb3Spatrick // though that memory might contain pointers to heap objects which will be
2823cab2bb3Spatrick // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
2833cab2bb3Spatrick // the TSD destructors have run might cause false positives in LSan.
2843cab2bb3Spatrick if (!SANITIZER_POSIX)
2853cab2bb3Spatrick this->Destroy();
2863cab2bb3Spatrick
2873cab2bb3Spatrick return res;
2883cab2bb3Spatrick }
2893cab2bb3Spatrick
CreateMainThread()2903cab2bb3Spatrick AsanThread *CreateMainThread() {
2913cab2bb3Spatrick AsanThread *main_thread = AsanThread::Create(
292d89ec533Spatrick /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ kMainTid,
2933cab2bb3Spatrick /* stack */ nullptr, /* detached */ true);
2943cab2bb3Spatrick SetCurrentThread(main_thread);
295d89ec533Spatrick main_thread->ThreadStart(internal_getpid());
2963cab2bb3Spatrick return main_thread;
2973cab2bb3Spatrick }
2983cab2bb3Spatrick
2993cab2bb3Spatrick // This implementation doesn't use the argument, which is just passed down
3003cab2bb3Spatrick // from the caller of Init (which see, above). It's only there to support
3013cab2bb3Spatrick // OS-specific implementations that need more information passed through.
SetThreadStackAndTls(const InitOptions * options)3023cab2bb3Spatrick void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
3033cab2bb3Spatrick DCHECK_EQ(options, nullptr);
3043cab2bb3Spatrick uptr tls_size = 0;
3053cab2bb3Spatrick uptr stack_size = 0;
306d89ec533Spatrick GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
307d89ec533Spatrick &tls_begin_, &tls_size);
308*810390e3Srobert stack_top_ = RoundDownTo(stack_bottom_ + stack_size, ASAN_SHADOW_GRANULARITY);
3093cab2bb3Spatrick tls_end_ = tls_begin_ + tls_size;
3103cab2bb3Spatrick dtls_ = DTLS_Get();
3113cab2bb3Spatrick
3123cab2bb3Spatrick if (stack_top_ != stack_bottom_) {
3133cab2bb3Spatrick int local;
3143cab2bb3Spatrick CHECK(AddrIsInStack((uptr)&local));
3153cab2bb3Spatrick }
3163cab2bb3Spatrick }
3173cab2bb3Spatrick
318d89ec533Spatrick #endif // !SANITIZER_FUCHSIA
3193cab2bb3Spatrick
ClearShadowForThreadStackAndTLS()3203cab2bb3Spatrick void AsanThread::ClearShadowForThreadStackAndTLS() {
3213cab2bb3Spatrick if (stack_top_ != stack_bottom_)
3223cab2bb3Spatrick PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
3233cab2bb3Spatrick if (tls_begin_ != tls_end_) {
324*810390e3Srobert uptr tls_begin_aligned = RoundDownTo(tls_begin_, ASAN_SHADOW_GRANULARITY);
325*810390e3Srobert uptr tls_end_aligned = RoundUpTo(tls_end_, ASAN_SHADOW_GRANULARITY);
326*810390e3Srobert FastPoisonShadow(tls_begin_aligned, tls_end_aligned - tls_begin_aligned, 0);
3273cab2bb3Spatrick }
3283cab2bb3Spatrick }
3293cab2bb3Spatrick
GetStackFrameAccessByAddr(uptr addr,StackFrameAccess * access)3303cab2bb3Spatrick bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
3313cab2bb3Spatrick StackFrameAccess *access) {
3323cab2bb3Spatrick if (stack_top_ == stack_bottom_)
3333cab2bb3Spatrick return false;
3343cab2bb3Spatrick
3353cab2bb3Spatrick uptr bottom = 0;
3363cab2bb3Spatrick if (AddrIsInStack(addr)) {
3373cab2bb3Spatrick bottom = stack_bottom();
338d89ec533Spatrick } else if (FakeStack *fake_stack = get_fake_stack()) {
339d89ec533Spatrick bottom = fake_stack->AddrIsInFakeStack(addr);
3403cab2bb3Spatrick CHECK(bottom);
3413cab2bb3Spatrick access->offset = addr - bottom;
3423cab2bb3Spatrick access->frame_pc = ((uptr*)bottom)[2];
3433cab2bb3Spatrick access->frame_descr = (const char *)((uptr*)bottom)[1];
3443cab2bb3Spatrick return true;
3453cab2bb3Spatrick }
3463cab2bb3Spatrick uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr.
347*810390e3Srobert uptr mem_ptr = RoundDownTo(aligned_addr, ASAN_SHADOW_GRANULARITY);
3483cab2bb3Spatrick u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
3493cab2bb3Spatrick u8 *shadow_bottom = (u8*)MemToShadow(bottom);
3503cab2bb3Spatrick
3513cab2bb3Spatrick while (shadow_ptr >= shadow_bottom &&
3523cab2bb3Spatrick *shadow_ptr != kAsanStackLeftRedzoneMagic) {
3533cab2bb3Spatrick shadow_ptr--;
354*810390e3Srobert mem_ptr -= ASAN_SHADOW_GRANULARITY;
3553cab2bb3Spatrick }
3563cab2bb3Spatrick
3573cab2bb3Spatrick while (shadow_ptr >= shadow_bottom &&
3583cab2bb3Spatrick *shadow_ptr == kAsanStackLeftRedzoneMagic) {
3593cab2bb3Spatrick shadow_ptr--;
360*810390e3Srobert mem_ptr -= ASAN_SHADOW_GRANULARITY;
3613cab2bb3Spatrick }
3623cab2bb3Spatrick
3633cab2bb3Spatrick if (shadow_ptr < shadow_bottom) {
3643cab2bb3Spatrick return false;
3653cab2bb3Spatrick }
3663cab2bb3Spatrick
367*810390e3Srobert uptr *ptr = (uptr *)(mem_ptr + ASAN_SHADOW_GRANULARITY);
3683cab2bb3Spatrick CHECK(ptr[0] == kCurrentStackFrameMagic);
3693cab2bb3Spatrick access->offset = addr - (uptr)ptr;
3703cab2bb3Spatrick access->frame_pc = ptr[2];
3713cab2bb3Spatrick access->frame_descr = (const char*)ptr[1];
3723cab2bb3Spatrick return true;
3733cab2bb3Spatrick }
3743cab2bb3Spatrick
GetStackVariableShadowStart(uptr addr)3753cab2bb3Spatrick uptr AsanThread::GetStackVariableShadowStart(uptr addr) {
3763cab2bb3Spatrick uptr bottom = 0;
3773cab2bb3Spatrick if (AddrIsInStack(addr)) {
3783cab2bb3Spatrick bottom = stack_bottom();
379d89ec533Spatrick } else if (FakeStack *fake_stack = get_fake_stack()) {
380d89ec533Spatrick bottom = fake_stack->AddrIsInFakeStack(addr);
381d89ec533Spatrick if (bottom == 0) {
382d89ec533Spatrick return 0;
383d89ec533Spatrick }
3843cab2bb3Spatrick } else {
3853cab2bb3Spatrick return 0;
3863cab2bb3Spatrick }
3873cab2bb3Spatrick
3883cab2bb3Spatrick uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr.
3893cab2bb3Spatrick u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
3903cab2bb3Spatrick u8 *shadow_bottom = (u8*)MemToShadow(bottom);
3913cab2bb3Spatrick
3923cab2bb3Spatrick while (shadow_ptr >= shadow_bottom &&
3933cab2bb3Spatrick (*shadow_ptr != kAsanStackLeftRedzoneMagic &&
3943cab2bb3Spatrick *shadow_ptr != kAsanStackMidRedzoneMagic &&
3953cab2bb3Spatrick *shadow_ptr != kAsanStackRightRedzoneMagic))
3963cab2bb3Spatrick shadow_ptr--;
3973cab2bb3Spatrick
3983cab2bb3Spatrick return (uptr)shadow_ptr + 1;
3993cab2bb3Spatrick }
4003cab2bb3Spatrick
AddrIsInStack(uptr addr)4013cab2bb3Spatrick bool AsanThread::AddrIsInStack(uptr addr) {
4023cab2bb3Spatrick const auto bounds = GetStackBounds();
4033cab2bb3Spatrick return addr >= bounds.bottom && addr < bounds.top;
4043cab2bb3Spatrick }
4053cab2bb3Spatrick
ThreadStackContainsAddress(ThreadContextBase * tctx_base,void * addr)4063cab2bb3Spatrick static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
4073cab2bb3Spatrick void *addr) {
4083cab2bb3Spatrick AsanThreadContext *tctx = static_cast<AsanThreadContext *>(tctx_base);
4093cab2bb3Spatrick AsanThread *t = tctx->thread;
410d89ec533Spatrick if (!t)
4113cab2bb3Spatrick return false;
412d89ec533Spatrick if (t->AddrIsInStack((uptr)addr))
413d89ec533Spatrick return true;
414d89ec533Spatrick FakeStack *fake_stack = t->get_fake_stack();
415d89ec533Spatrick if (!fake_stack)
416d89ec533Spatrick return false;
417d89ec533Spatrick return fake_stack->AddrIsInFakeStack((uptr)addr);
4183cab2bb3Spatrick }
4193cab2bb3Spatrick
GetCurrentThread()4203cab2bb3Spatrick AsanThread *GetCurrentThread() {
4213cab2bb3Spatrick AsanThreadContext *context =
4223cab2bb3Spatrick reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
4233cab2bb3Spatrick if (!context) {
4243cab2bb3Spatrick if (SANITIZER_ANDROID) {
4253cab2bb3Spatrick // On Android, libc constructor is called _after_ asan_init, and cleans up
4263cab2bb3Spatrick // TSD. Try to figure out if this is still the main thread by the stack
4273cab2bb3Spatrick // address. We are not entirely sure that we have correct main thread
4283cab2bb3Spatrick // limits, so only do this magic on Android, and only if the found thread
4293cab2bb3Spatrick // is the main thread.
430d89ec533Spatrick AsanThreadContext *tctx = GetThreadContextByTidLocked(kMainTid);
4313cab2bb3Spatrick if (tctx && ThreadStackContainsAddress(tctx, &context)) {
4323cab2bb3Spatrick SetCurrentThread(tctx->thread);
4333cab2bb3Spatrick return tctx->thread;
4343cab2bb3Spatrick }
4353cab2bb3Spatrick }
4363cab2bb3Spatrick return nullptr;
4373cab2bb3Spatrick }
4383cab2bb3Spatrick return context->thread;
4393cab2bb3Spatrick }
4403cab2bb3Spatrick
SetCurrentThread(AsanThread * t)4413cab2bb3Spatrick void SetCurrentThread(AsanThread *t) {
4423cab2bb3Spatrick CHECK(t->context());
443*810390e3Srobert VReport(2, "SetCurrentThread: %p for thread %p\n", (void *)t->context(),
4443cab2bb3Spatrick (void *)GetThreadSelf());
4453cab2bb3Spatrick // Make sure we do not reset the current AsanThread.
4463cab2bb3Spatrick CHECK_EQ(0, AsanTSDGet());
4473cab2bb3Spatrick AsanTSDSet(t->context());
4483cab2bb3Spatrick CHECK_EQ(t->context(), AsanTSDGet());
4493cab2bb3Spatrick }
4503cab2bb3Spatrick
GetCurrentTidOrInvalid()4513cab2bb3Spatrick u32 GetCurrentTidOrInvalid() {
4523cab2bb3Spatrick AsanThread *t = GetCurrentThread();
4533cab2bb3Spatrick return t ? t->tid() : kInvalidTid;
4543cab2bb3Spatrick }
4553cab2bb3Spatrick
FindThreadByStackAddress(uptr addr)4563cab2bb3Spatrick AsanThread *FindThreadByStackAddress(uptr addr) {
4573cab2bb3Spatrick asanThreadRegistry().CheckLocked();
4583cab2bb3Spatrick AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
4593cab2bb3Spatrick asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
4603cab2bb3Spatrick (void *)addr));
4613cab2bb3Spatrick return tctx ? tctx->thread : nullptr;
4623cab2bb3Spatrick }
4633cab2bb3Spatrick
EnsureMainThreadIDIsCorrect()4643cab2bb3Spatrick void EnsureMainThreadIDIsCorrect() {
4653cab2bb3Spatrick AsanThreadContext *context =
4663cab2bb3Spatrick reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
467d89ec533Spatrick if (context && (context->tid == kMainTid))
4683cab2bb3Spatrick context->os_id = GetTid();
4693cab2bb3Spatrick }
4703cab2bb3Spatrick
GetAsanThreadByOsIDLocked(tid_t os_id)4713cab2bb3Spatrick __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) {
4723cab2bb3Spatrick __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
4733cab2bb3Spatrick __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
4743cab2bb3Spatrick if (!context) return nullptr;
4753cab2bb3Spatrick return context->thread;
4763cab2bb3Spatrick }
4773cab2bb3Spatrick } // namespace __asan
4783cab2bb3Spatrick
4793cab2bb3Spatrick // --- Implementation of LSan-specific functions --- {{{1
4803cab2bb3Spatrick namespace __lsan {
LockThreadRegistry()481*810390e3Srobert void LockThreadRegistry() { __asan::asanThreadRegistry().Lock(); }
482*810390e3Srobert
UnlockThreadRegistry()483*810390e3Srobert void UnlockThreadRegistry() { __asan::asanThreadRegistry().Unlock(); }
484*810390e3Srobert
GetAsanThreadRegistryLocked()485*810390e3Srobert static ThreadRegistry *GetAsanThreadRegistryLocked() {
486*810390e3Srobert __asan::asanThreadRegistry().CheckLocked();
487*810390e3Srobert return &__asan::asanThreadRegistry();
488*810390e3Srobert }
489*810390e3Srobert
EnsureMainThreadIDIsCorrect()490*810390e3Srobert void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); }
491*810390e3Srobert
GetThreadRangesLocked(tid_t os_id,uptr * stack_begin,uptr * stack_end,uptr * tls_begin,uptr * tls_end,uptr * cache_begin,uptr * cache_end,DTLS ** dtls)4923cab2bb3Spatrick bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
4933cab2bb3Spatrick uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
4943cab2bb3Spatrick uptr *cache_end, DTLS **dtls) {
4953cab2bb3Spatrick __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
4963cab2bb3Spatrick if (!t) return false;
4973cab2bb3Spatrick *stack_begin = t->stack_bottom();
4983cab2bb3Spatrick *stack_end = t->stack_top();
4993cab2bb3Spatrick *tls_begin = t->tls_begin();
5003cab2bb3Spatrick *tls_end = t->tls_end();
5013cab2bb3Spatrick // ASan doesn't keep allocator caches in TLS, so these are unused.
5023cab2bb3Spatrick *cache_begin = 0;
5033cab2bb3Spatrick *cache_end = 0;
5043cab2bb3Spatrick *dtls = t->dtls();
5053cab2bb3Spatrick return true;
5063cab2bb3Spatrick }
5073cab2bb3Spatrick
GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> * caches)5081f9cb04fSpatrick void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
5091f9cb04fSpatrick
GetThreadExtraStackRangesLocked(tid_t os_id,InternalMmapVector<Range> * ranges)510*810390e3Srobert void GetThreadExtraStackRangesLocked(tid_t os_id,
511*810390e3Srobert InternalMmapVector<Range> *ranges) {
5123cab2bb3Spatrick __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
513d89ec533Spatrick if (!t)
514d89ec533Spatrick return;
515d89ec533Spatrick __asan::FakeStack *fake_stack = t->get_fake_stack();
516d89ec533Spatrick if (!fake_stack)
517d89ec533Spatrick return;
518*810390e3Srobert
519*810390e3Srobert fake_stack->ForEachFakeFrame(
520*810390e3Srobert [](uptr begin, uptr end, void *arg) {
521*810390e3Srobert reinterpret_cast<InternalMmapVector<Range> *>(arg)->push_back(
522*810390e3Srobert {begin, end});
523*810390e3Srobert },
524*810390e3Srobert ranges);
5253cab2bb3Spatrick }
5263cab2bb3Spatrick
GetThreadExtraStackRangesLocked(InternalMmapVector<Range> * ranges)527*810390e3Srobert void GetThreadExtraStackRangesLocked(InternalMmapVector<Range> *ranges) {
528*810390e3Srobert GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
529*810390e3Srobert [](ThreadContextBase *tctx, void *arg) {
530*810390e3Srobert GetThreadExtraStackRangesLocked(
531*810390e3Srobert tctx->os_id, reinterpret_cast<InternalMmapVector<Range> *>(arg));
532*810390e3Srobert },
533*810390e3Srobert ranges);
5343cab2bb3Spatrick }
5353cab2bb3Spatrick
GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> * ptrs)536*810390e3Srobert void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
537*810390e3Srobert GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
538*810390e3Srobert [](ThreadContextBase *tctx, void *ptrs) {
539*810390e3Srobert // Look for the arg pointer of threads that have been created or are
540*810390e3Srobert // running. This is necessary to prevent false positive leaks due to the
541*810390e3Srobert // AsanThread holding the only live reference to a heap object. This
542*810390e3Srobert // can happen because the `pthread_create()` interceptor doesn't wait
543*810390e3Srobert // for the child thread to start before returning and thus loosing the
544*810390e3Srobert // the only live reference to the heap object on the stack.
545*810390e3Srobert
546*810390e3Srobert __asan::AsanThreadContext *atctx =
547*810390e3Srobert static_cast<__asan::AsanThreadContext *>(tctx);
548*810390e3Srobert
549*810390e3Srobert // Note ThreadStatusRunning is required because there is a small window
550*810390e3Srobert // where the thread status switches to `ThreadStatusRunning` but the
551*810390e3Srobert // `arg` pointer still isn't on the stack yet.
552*810390e3Srobert if (atctx->status != ThreadStatusCreated &&
553*810390e3Srobert atctx->status != ThreadStatusRunning)
554*810390e3Srobert return;
555*810390e3Srobert
556*810390e3Srobert uptr thread_arg = reinterpret_cast<uptr>(atctx->thread->get_arg());
557*810390e3Srobert if (!thread_arg)
558*810390e3Srobert return;
559*810390e3Srobert
560*810390e3Srobert auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
561*810390e3Srobert ptrsVec->push_back(thread_arg);
562*810390e3Srobert },
563*810390e3Srobert ptrs);
5643cab2bb3Spatrick }
5653cab2bb3Spatrick
GetRunningThreadsLocked(InternalMmapVector<tid_t> * threads)566*810390e3Srobert void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
567*810390e3Srobert GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
568*810390e3Srobert [](ThreadContextBase *tctx, void *threads) {
569*810390e3Srobert if (tctx->status == ThreadStatusRunning)
570*810390e3Srobert reinterpret_cast<InternalMmapVector<tid_t> *>(threads)->push_back(
571*810390e3Srobert tctx->os_id);
572*810390e3Srobert },
573*810390e3Srobert threads);
5743cab2bb3Spatrick }
5753cab2bb3Spatrick
FinishThreadLocked(u32 tid)576*810390e3Srobert void FinishThreadLocked(u32 tid) {
577*810390e3Srobert GetAsanThreadRegistryLocked()->FinishThread(tid);
5783cab2bb3Spatrick }
579*810390e3Srobert
5803cab2bb3Spatrick } // namespace __lsan
5813cab2bb3Spatrick
5823cab2bb3Spatrick // ---------------------- Interface ---------------- {{{1
5833cab2bb3Spatrick using namespace __asan;
5843cab2bb3Spatrick
5853cab2bb3Spatrick extern "C" {
5863cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_start_switch_fiber(void ** fakestacksave,const void * bottom,uptr size)5873cab2bb3Spatrick void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom,
5883cab2bb3Spatrick uptr size) {
5893cab2bb3Spatrick AsanThread *t = GetCurrentThread();
5903cab2bb3Spatrick if (!t) {
5913cab2bb3Spatrick VReport(1, "__asan_start_switch_fiber called from unknown thread\n");
5923cab2bb3Spatrick return;
5933cab2bb3Spatrick }
5943cab2bb3Spatrick t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size);
5953cab2bb3Spatrick }
5963cab2bb3Spatrick
5973cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_finish_switch_fiber(void * fakestack,const void ** bottom_old,uptr * size_old)5983cab2bb3Spatrick void __sanitizer_finish_switch_fiber(void* fakestack,
5993cab2bb3Spatrick const void **bottom_old,
6003cab2bb3Spatrick uptr *size_old) {
6013cab2bb3Spatrick AsanThread *t = GetCurrentThread();
6023cab2bb3Spatrick if (!t) {
6033cab2bb3Spatrick VReport(1, "__asan_finish_switch_fiber called from unknown thread\n");
6043cab2bb3Spatrick return;
6053cab2bb3Spatrick }
6063cab2bb3Spatrick t->FinishSwitchFiber((FakeStack*)fakestack,
6073cab2bb3Spatrick (uptr*)bottom_old,
6083cab2bb3Spatrick (uptr*)size_old);
6093cab2bb3Spatrick }
6103cab2bb3Spatrick }
611