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
OnCreated(void * arg)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
OnFinished()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
GetAsanThreadContext(u32 tid)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
InitThreads()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
asanThreadRegistry()8106c3fb27SDimitry Andric ThreadRegistry &asanThreadRegistry() {
8206c3fb27SDimitry Andric InitThreads();
8368d75effSDimitry Andric return *asan_thread_registry;
8468d75effSDimitry Andric }
8568d75effSDimitry Andric
asanThreadArgRetval()8606c3fb27SDimitry Andric ThreadArgRetval &asanThreadArgRetval() {
8706c3fb27SDimitry Andric InitThreads();
8806c3fb27SDimitry Andric return *thread_data;
8906c3fb27SDimitry Andric }
9006c3fb27SDimitry Andric
GetThreadContextByTidLocked(u32 tid)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
Create(const void * start_data,uptr data_size,u32 parent_tid,StackTrace * stack,bool detached)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
GetStartData(void * out,uptr out_size) const1155f757f3fSDimitry Andric void AsanThread::GetStartData(void *out, uptr out_size) const {
1165f757f3fSDimitry Andric internal_memcpy(out, start_data_, out_size);
1175f757f3fSDimitry Andric }
1185f757f3fSDimitry Andric
TSDDtor(void * tsd)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
Destroy()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
StartSwitchFiber(FakeStack ** fake_stack_save,uptr bottom,uptr size)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
FinishSwitchFiber(FakeStack * fake_stack_save,uptr * bottom_old,uptr * size_old)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
GetStackBounds() const19768d75effSDimitry 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
stack_top()21406c3fb27SDimitry Andric uptr AsanThread::stack_top() { return GetStackBounds().top; }
21568d75effSDimitry Andric
stack_bottom()21606c3fb27SDimitry Andric uptr AsanThread::stack_bottom() { return GetStackBounds().bottom; }
21768d75effSDimitry Andric
stack_size()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.
AsyncSignalSafeLazyInitFakeStack()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
Init(const InitOptions * options)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
ThreadStart(tid_t os_id)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
CreateMainThread()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.
SetThreadStackAndTls(const InitOptions * options)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
ClearShadowForThreadStackAndTLS()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
GetStackFrameAccessByAddr(uptr addr,StackFrameAccess * access)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
GetStackVariableShadowStart(uptr addr)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
AddrIsInStack(uptr addr)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
ThreadStackContainsAddress(ThreadContextBase * tctx_base,void * addr)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
GetCurrentThread()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
SetCurrentThread(AsanThread * t)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
GetCurrentTidOrInvalid()45768d75effSDimitry Andric u32 GetCurrentTidOrInvalid() {
45868d75effSDimitry Andric AsanThread *t = GetCurrentThread();
45968d75effSDimitry Andric return t ? t->tid() : kInvalidTid;
46068d75effSDimitry Andric }
46168d75effSDimitry Andric
FindThreadByStackAddress(uptr addr)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
EnsureMainThreadIDIsCorrect()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
GetAsanThreadByOsIDLocked(tid_t os_id)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 {
LockThreads()48806c3fb27SDimitry Andric void LockThreads() {
48906c3fb27SDimitry Andric __asan::asanThreadRegistry().Lock();
49006c3fb27SDimitry Andric __asan::asanThreadArgRetval().Lock();
49106c3fb27SDimitry Andric }
492bdd1243dSDimitry Andric
UnlockThreads()49306c3fb27SDimitry Andric void UnlockThreads() {
49406c3fb27SDimitry Andric __asan::asanThreadArgRetval().Unlock();
49506c3fb27SDimitry Andric __asan::asanThreadRegistry().Unlock();
49606c3fb27SDimitry Andric }
497bdd1243dSDimitry Andric
GetAsanThreadRegistryLocked()498bdd1243dSDimitry Andric static ThreadRegistry *GetAsanThreadRegistryLocked() {
499bdd1243dSDimitry Andric __asan::asanThreadRegistry().CheckLocked();
500bdd1243dSDimitry Andric return &__asan::asanThreadRegistry();
501bdd1243dSDimitry Andric }
502bdd1243dSDimitry Andric
EnsureMainThreadIDIsCorrect()503bdd1243dSDimitry Andric void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); }
504bdd1243dSDimitry Andric
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)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
GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> * caches)5225ffd83dbSDimitry Andric void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
5235ffd83dbSDimitry Andric
GetThreadExtraStackRangesLocked(tid_t os_id,InternalMmapVector<Range> * ranges)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
GetThreadExtraStackRangesLocked(InternalMmapVector<Range> * ranges)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
GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> * ptrs)550bdd1243dSDimitry Andric void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
55106c3fb27SDimitry Andric __asan::asanThreadArgRetval().GetAllPtrsLocked(ptrs);
55268d75effSDimitry Andric }
55368d75effSDimitry Andric
GetRunningThreadsLocked(InternalMmapVector<tid_t> * threads)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
__sanitizer_start_switch_fiber(void ** fakestacksave,const void * bottom,uptr size)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
__sanitizer_finish_switch_fiber(void * fakestack,const void ** bottom_old,uptr * size_old)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