xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/asan/asan_thread.cpp (revision 68d75eff68281c1b445e3010bb975eae07aac225)
1*68d75effSDimitry Andric //===-- asan_thread.cpp ---------------------------------------------------===//
2*68d75effSDimitry Andric //
3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*68d75effSDimitry Andric //
7*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
8*68d75effSDimitry Andric //
9*68d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
10*68d75effSDimitry Andric //
11*68d75effSDimitry Andric // Thread-related code.
12*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
13*68d75effSDimitry Andric #include "asan_allocator.h"
14*68d75effSDimitry Andric #include "asan_interceptors.h"
15*68d75effSDimitry Andric #include "asan_poisoning.h"
16*68d75effSDimitry Andric #include "asan_stack.h"
17*68d75effSDimitry Andric #include "asan_thread.h"
18*68d75effSDimitry Andric #include "asan_mapping.h"
19*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
20*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
21*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
22*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_tls_get_addr.h"
23*68d75effSDimitry Andric #include "lsan/lsan_common.h"
24*68d75effSDimitry Andric 
25*68d75effSDimitry Andric namespace __asan {
26*68d75effSDimitry Andric 
27*68d75effSDimitry Andric // AsanThreadContext implementation.
28*68d75effSDimitry Andric 
29*68d75effSDimitry Andric void AsanThreadContext::OnCreated(void *arg) {
30*68d75effSDimitry Andric   CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
31*68d75effSDimitry Andric   if (args->stack)
32*68d75effSDimitry Andric     stack_id = StackDepotPut(*args->stack);
33*68d75effSDimitry Andric   thread = args->thread;
34*68d75effSDimitry Andric   thread->set_context(this);
35*68d75effSDimitry Andric }
36*68d75effSDimitry Andric 
37*68d75effSDimitry Andric void AsanThreadContext::OnFinished() {
38*68d75effSDimitry Andric   // Drop the link to the AsanThread object.
39*68d75effSDimitry Andric   thread = nullptr;
40*68d75effSDimitry Andric }
41*68d75effSDimitry Andric 
42*68d75effSDimitry Andric // MIPS requires aligned address
43*68d75effSDimitry Andric static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
44*68d75effSDimitry Andric static ThreadRegistry *asan_thread_registry;
45*68d75effSDimitry Andric 
46*68d75effSDimitry Andric static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED);
47*68d75effSDimitry Andric static LowLevelAllocator allocator_for_thread_context;
48*68d75effSDimitry Andric 
49*68d75effSDimitry Andric static ThreadContextBase *GetAsanThreadContext(u32 tid) {
50*68d75effSDimitry Andric   BlockingMutexLock lock(&mu_for_thread_context);
51*68d75effSDimitry Andric   return new(allocator_for_thread_context) AsanThreadContext(tid);
52*68d75effSDimitry Andric }
53*68d75effSDimitry Andric 
54*68d75effSDimitry Andric ThreadRegistry &asanThreadRegistry() {
55*68d75effSDimitry Andric   static bool initialized;
56*68d75effSDimitry Andric   // Don't worry about thread_safety - this should be called when there is
57*68d75effSDimitry Andric   // a single thread.
58*68d75effSDimitry Andric   if (!initialized) {
59*68d75effSDimitry Andric     // Never reuse ASan threads: we store pointer to AsanThreadContext
60*68d75effSDimitry Andric     // in TSD and can't reliably tell when no more TSD destructors will
61*68d75effSDimitry Andric     // be called. It would be wrong to reuse AsanThreadContext for another
62*68d75effSDimitry Andric     // thread before all TSD destructors will be called for it.
63*68d75effSDimitry Andric     asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry(
64*68d75effSDimitry Andric         GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads);
65*68d75effSDimitry Andric     initialized = true;
66*68d75effSDimitry Andric   }
67*68d75effSDimitry Andric   return *asan_thread_registry;
68*68d75effSDimitry Andric }
69*68d75effSDimitry Andric 
70*68d75effSDimitry Andric AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
71*68d75effSDimitry Andric   return static_cast<AsanThreadContext *>(
72*68d75effSDimitry Andric       asanThreadRegistry().GetThreadLocked(tid));
73*68d75effSDimitry Andric }
74*68d75effSDimitry Andric 
75*68d75effSDimitry Andric // AsanThread implementation.
76*68d75effSDimitry Andric 
77*68d75effSDimitry Andric AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
78*68d75effSDimitry Andric                                u32 parent_tid, StackTrace *stack,
79*68d75effSDimitry Andric                                bool detached) {
80*68d75effSDimitry Andric   uptr PageSize = GetPageSizeCached();
81*68d75effSDimitry Andric   uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
82*68d75effSDimitry Andric   AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
83*68d75effSDimitry Andric   thread->start_routine_ = start_routine;
84*68d75effSDimitry Andric   thread->arg_ = arg;
85*68d75effSDimitry Andric   AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
86*68d75effSDimitry Andric   asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
87*68d75effSDimitry Andric                                     parent_tid, &args);
88*68d75effSDimitry Andric 
89*68d75effSDimitry Andric   return thread;
90*68d75effSDimitry Andric }
91*68d75effSDimitry Andric 
92*68d75effSDimitry Andric void AsanThread::TSDDtor(void *tsd) {
93*68d75effSDimitry Andric   AsanThreadContext *context = (AsanThreadContext*)tsd;
94*68d75effSDimitry Andric   VReport(1, "T%d TSDDtor\n", context->tid);
95*68d75effSDimitry Andric   if (context->thread)
96*68d75effSDimitry Andric     context->thread->Destroy();
97*68d75effSDimitry Andric }
98*68d75effSDimitry Andric 
99*68d75effSDimitry Andric void AsanThread::Destroy() {
100*68d75effSDimitry Andric   int tid = this->tid();
101*68d75effSDimitry Andric   VReport(1, "T%d exited\n", tid);
102*68d75effSDimitry Andric 
103*68d75effSDimitry Andric   malloc_storage().CommitBack();
104*68d75effSDimitry Andric   if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
105*68d75effSDimitry Andric   asanThreadRegistry().FinishThread(tid);
106*68d75effSDimitry Andric   FlushToDeadThreadStats(&stats_);
107*68d75effSDimitry Andric   // We also clear the shadow on thread destruction because
108*68d75effSDimitry Andric   // some code may still be executing in later TSD destructors
109*68d75effSDimitry Andric   // and we don't want it to have any poisoned stack.
110*68d75effSDimitry Andric   ClearShadowForThreadStackAndTLS();
111*68d75effSDimitry Andric   DeleteFakeStack(tid);
112*68d75effSDimitry Andric   uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
113*68d75effSDimitry Andric   UnmapOrDie(this, size);
114*68d75effSDimitry Andric   DTLS_Destroy();
115*68d75effSDimitry Andric }
116*68d75effSDimitry Andric 
117*68d75effSDimitry Andric void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
118*68d75effSDimitry Andric                                   uptr size) {
119*68d75effSDimitry Andric   if (atomic_load(&stack_switching_, memory_order_relaxed)) {
120*68d75effSDimitry Andric     Report("ERROR: starting fiber switch while in fiber switch\n");
121*68d75effSDimitry Andric     Die();
122*68d75effSDimitry Andric   }
123*68d75effSDimitry Andric 
124*68d75effSDimitry Andric   next_stack_bottom_ = bottom;
125*68d75effSDimitry Andric   next_stack_top_ = bottom + size;
126*68d75effSDimitry Andric   atomic_store(&stack_switching_, 1, memory_order_release);
127*68d75effSDimitry Andric 
128*68d75effSDimitry Andric   FakeStack *current_fake_stack = fake_stack_;
129*68d75effSDimitry Andric   if (fake_stack_save)
130*68d75effSDimitry Andric     *fake_stack_save = fake_stack_;
131*68d75effSDimitry Andric   fake_stack_ = nullptr;
132*68d75effSDimitry Andric   SetTLSFakeStack(nullptr);
133*68d75effSDimitry Andric   // if fake_stack_save is null, the fiber will die, delete the fakestack
134*68d75effSDimitry Andric   if (!fake_stack_save && current_fake_stack)
135*68d75effSDimitry Andric     current_fake_stack->Destroy(this->tid());
136*68d75effSDimitry Andric }
137*68d75effSDimitry Andric 
138*68d75effSDimitry Andric void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save,
139*68d75effSDimitry Andric                                    uptr *bottom_old,
140*68d75effSDimitry Andric                                    uptr *size_old) {
141*68d75effSDimitry Andric   if (!atomic_load(&stack_switching_, memory_order_relaxed)) {
142*68d75effSDimitry Andric     Report("ERROR: finishing a fiber switch that has not started\n");
143*68d75effSDimitry Andric     Die();
144*68d75effSDimitry Andric   }
145*68d75effSDimitry Andric 
146*68d75effSDimitry Andric   if (fake_stack_save) {
147*68d75effSDimitry Andric     SetTLSFakeStack(fake_stack_save);
148*68d75effSDimitry Andric     fake_stack_ = fake_stack_save;
149*68d75effSDimitry Andric   }
150*68d75effSDimitry Andric 
151*68d75effSDimitry Andric   if (bottom_old)
152*68d75effSDimitry Andric     *bottom_old = stack_bottom_;
153*68d75effSDimitry Andric   if (size_old)
154*68d75effSDimitry Andric     *size_old = stack_top_ - stack_bottom_;
155*68d75effSDimitry Andric   stack_bottom_ = next_stack_bottom_;
156*68d75effSDimitry Andric   stack_top_ = next_stack_top_;
157*68d75effSDimitry Andric   atomic_store(&stack_switching_, 0, memory_order_release);
158*68d75effSDimitry Andric   next_stack_top_ = 0;
159*68d75effSDimitry Andric   next_stack_bottom_ = 0;
160*68d75effSDimitry Andric }
161*68d75effSDimitry Andric 
162*68d75effSDimitry Andric inline AsanThread::StackBounds AsanThread::GetStackBounds() const {
163*68d75effSDimitry Andric   if (!atomic_load(&stack_switching_, memory_order_acquire)) {
164*68d75effSDimitry Andric     // Make sure the stack bounds are fully initialized.
165*68d75effSDimitry Andric     if (stack_bottom_ >= stack_top_) return {0, 0};
166*68d75effSDimitry Andric     return {stack_bottom_, stack_top_};
167*68d75effSDimitry Andric   }
168*68d75effSDimitry Andric   char local;
169*68d75effSDimitry Andric   const uptr cur_stack = (uptr)&local;
170*68d75effSDimitry Andric   // Note: need to check next stack first, because FinishSwitchFiber
171*68d75effSDimitry Andric   // may be in process of overwriting stack_top_/bottom_. But in such case
172*68d75effSDimitry Andric   // we are already on the next stack.
173*68d75effSDimitry Andric   if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_)
174*68d75effSDimitry Andric     return {next_stack_bottom_, next_stack_top_};
175*68d75effSDimitry Andric   return {stack_bottom_, stack_top_};
176*68d75effSDimitry Andric }
177*68d75effSDimitry Andric 
178*68d75effSDimitry Andric uptr AsanThread::stack_top() {
179*68d75effSDimitry Andric   return GetStackBounds().top;
180*68d75effSDimitry Andric }
181*68d75effSDimitry Andric 
182*68d75effSDimitry Andric uptr AsanThread::stack_bottom() {
183*68d75effSDimitry Andric   return GetStackBounds().bottom;
184*68d75effSDimitry Andric }
185*68d75effSDimitry Andric 
186*68d75effSDimitry Andric uptr AsanThread::stack_size() {
187*68d75effSDimitry Andric   const auto bounds = GetStackBounds();
188*68d75effSDimitry Andric   return bounds.top - bounds.bottom;
189*68d75effSDimitry Andric }
190*68d75effSDimitry Andric 
191*68d75effSDimitry Andric // We want to create the FakeStack lazyly on the first use, but not eralier
192*68d75effSDimitry Andric // than the stack size is known and the procedure has to be async-signal safe.
193*68d75effSDimitry Andric FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
194*68d75effSDimitry Andric   uptr stack_size = this->stack_size();
195*68d75effSDimitry Andric   if (stack_size == 0)  // stack_size is not yet available, don't use FakeStack.
196*68d75effSDimitry Andric     return nullptr;
197*68d75effSDimitry Andric   uptr old_val = 0;
198*68d75effSDimitry Andric   // fake_stack_ has 3 states:
199*68d75effSDimitry Andric   // 0   -- not initialized
200*68d75effSDimitry Andric   // 1   -- being initialized
201*68d75effSDimitry Andric   // ptr -- initialized
202*68d75effSDimitry Andric   // This CAS checks if the state was 0 and if so changes it to state 1,
203*68d75effSDimitry Andric   // if that was successful, it initializes the pointer.
204*68d75effSDimitry Andric   if (atomic_compare_exchange_strong(
205*68d75effSDimitry Andric       reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL,
206*68d75effSDimitry Andric       memory_order_relaxed)) {
207*68d75effSDimitry Andric     uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size));
208*68d75effSDimitry Andric     CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
209*68d75effSDimitry Andric     stack_size_log =
210*68d75effSDimitry Andric         Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log));
211*68d75effSDimitry Andric     stack_size_log =
212*68d75effSDimitry Andric         Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
213*68d75effSDimitry Andric     fake_stack_ = FakeStack::Create(stack_size_log);
214*68d75effSDimitry Andric     SetTLSFakeStack(fake_stack_);
215*68d75effSDimitry Andric     return fake_stack_;
216*68d75effSDimitry Andric   }
217*68d75effSDimitry Andric   return nullptr;
218*68d75effSDimitry Andric }
219*68d75effSDimitry Andric 
220*68d75effSDimitry Andric void AsanThread::Init(const InitOptions *options) {
221*68d75effSDimitry Andric   next_stack_top_ = next_stack_bottom_ = 0;
222*68d75effSDimitry Andric   atomic_store(&stack_switching_, false, memory_order_release);
223*68d75effSDimitry Andric   CHECK_EQ(this->stack_size(), 0U);
224*68d75effSDimitry Andric   SetThreadStackAndTls(options);
225*68d75effSDimitry Andric   if (stack_top_ != stack_bottom_) {
226*68d75effSDimitry Andric     CHECK_GT(this->stack_size(), 0U);
227*68d75effSDimitry Andric     CHECK(AddrIsInMem(stack_bottom_));
228*68d75effSDimitry Andric     CHECK(AddrIsInMem(stack_top_ - 1));
229*68d75effSDimitry Andric   }
230*68d75effSDimitry Andric   ClearShadowForThreadStackAndTLS();
231*68d75effSDimitry Andric   fake_stack_ = nullptr;
232*68d75effSDimitry Andric   if (__asan_option_detect_stack_use_after_return)
233*68d75effSDimitry Andric     AsyncSignalSafeLazyInitFakeStack();
234*68d75effSDimitry Andric   int local = 0;
235*68d75effSDimitry Andric   VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
236*68d75effSDimitry Andric           (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
237*68d75effSDimitry Andric           &local);
238*68d75effSDimitry Andric }
239*68d75effSDimitry Andric 
240*68d75effSDimitry Andric // Fuchsia and RTEMS don't use ThreadStart.
241*68d75effSDimitry Andric // asan_fuchsia.c/asan_rtems.c define CreateMainThread and
242*68d75effSDimitry Andric // SetThreadStackAndTls.
243*68d75effSDimitry Andric #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
244*68d75effSDimitry Andric 
245*68d75effSDimitry Andric thread_return_t AsanThread::ThreadStart(
246*68d75effSDimitry Andric     tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
247*68d75effSDimitry Andric   Init();
248*68d75effSDimitry Andric   asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
249*68d75effSDimitry Andric   if (signal_thread_is_registered)
250*68d75effSDimitry Andric     atomic_store(signal_thread_is_registered, 1, memory_order_release);
251*68d75effSDimitry Andric 
252*68d75effSDimitry Andric   if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
253*68d75effSDimitry Andric 
254*68d75effSDimitry Andric   if (!start_routine_) {
255*68d75effSDimitry Andric     // start_routine_ == 0 if we're on the main thread or on one of the
256*68d75effSDimitry Andric     // OS X libdispatch worker threads. But nobody is supposed to call
257*68d75effSDimitry Andric     // ThreadStart() for the worker threads.
258*68d75effSDimitry Andric     CHECK_EQ(tid(), 0);
259*68d75effSDimitry Andric     return 0;
260*68d75effSDimitry Andric   }
261*68d75effSDimitry Andric 
262*68d75effSDimitry Andric   thread_return_t res = start_routine_(arg_);
263*68d75effSDimitry Andric 
264*68d75effSDimitry Andric   // On POSIX systems we defer this to the TSD destructor. LSan will consider
265*68d75effSDimitry Andric   // the thread's memory as non-live from the moment we call Destroy(), even
266*68d75effSDimitry Andric   // though that memory might contain pointers to heap objects which will be
267*68d75effSDimitry Andric   // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
268*68d75effSDimitry Andric   // the TSD destructors have run might cause false positives in LSan.
269*68d75effSDimitry Andric   if (!SANITIZER_POSIX)
270*68d75effSDimitry Andric     this->Destroy();
271*68d75effSDimitry Andric 
272*68d75effSDimitry Andric   return res;
273*68d75effSDimitry Andric }
274*68d75effSDimitry Andric 
275*68d75effSDimitry Andric AsanThread *CreateMainThread() {
276*68d75effSDimitry Andric   AsanThread *main_thread = AsanThread::Create(
277*68d75effSDimitry Andric       /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
278*68d75effSDimitry Andric       /* stack */ nullptr, /* detached */ true);
279*68d75effSDimitry Andric   SetCurrentThread(main_thread);
280*68d75effSDimitry Andric   main_thread->ThreadStart(internal_getpid(),
281*68d75effSDimitry Andric                            /* signal_thread_is_registered */ nullptr);
282*68d75effSDimitry Andric   return main_thread;
283*68d75effSDimitry Andric }
284*68d75effSDimitry Andric 
285*68d75effSDimitry Andric // This implementation doesn't use the argument, which is just passed down
286*68d75effSDimitry Andric // from the caller of Init (which see, above).  It's only there to support
287*68d75effSDimitry Andric // OS-specific implementations that need more information passed through.
288*68d75effSDimitry Andric void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
289*68d75effSDimitry Andric   DCHECK_EQ(options, nullptr);
290*68d75effSDimitry Andric   uptr tls_size = 0;
291*68d75effSDimitry Andric   uptr stack_size = 0;
292*68d75effSDimitry Andric   GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
293*68d75effSDimitry Andric                        &tls_size);
294*68d75effSDimitry Andric   stack_top_ = stack_bottom_ + stack_size;
295*68d75effSDimitry Andric   tls_end_ = tls_begin_ + tls_size;
296*68d75effSDimitry Andric   dtls_ = DTLS_Get();
297*68d75effSDimitry Andric 
298*68d75effSDimitry Andric   if (stack_top_ != stack_bottom_) {
299*68d75effSDimitry Andric     int local;
300*68d75effSDimitry Andric     CHECK(AddrIsInStack((uptr)&local));
301*68d75effSDimitry Andric   }
302*68d75effSDimitry Andric }
303*68d75effSDimitry Andric 
304*68d75effSDimitry Andric #endif  // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
305*68d75effSDimitry Andric 
306*68d75effSDimitry Andric void AsanThread::ClearShadowForThreadStackAndTLS() {
307*68d75effSDimitry Andric   if (stack_top_ != stack_bottom_)
308*68d75effSDimitry Andric     PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
309*68d75effSDimitry Andric   if (tls_begin_ != tls_end_) {
310*68d75effSDimitry Andric     uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY);
311*68d75effSDimitry Andric     uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY);
312*68d75effSDimitry Andric     FastPoisonShadowPartialRightRedzone(tls_begin_aligned,
313*68d75effSDimitry Andric                                         tls_end_ - tls_begin_aligned,
314*68d75effSDimitry Andric                                         tls_end_aligned - tls_end_, 0);
315*68d75effSDimitry Andric   }
316*68d75effSDimitry Andric }
317*68d75effSDimitry Andric 
318*68d75effSDimitry Andric bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
319*68d75effSDimitry Andric                                            StackFrameAccess *access) {
320*68d75effSDimitry Andric   if (stack_top_ == stack_bottom_)
321*68d75effSDimitry Andric     return false;
322*68d75effSDimitry Andric 
323*68d75effSDimitry Andric   uptr bottom = 0;
324*68d75effSDimitry Andric   if (AddrIsInStack(addr)) {
325*68d75effSDimitry Andric     bottom = stack_bottom();
326*68d75effSDimitry Andric   } else if (has_fake_stack()) {
327*68d75effSDimitry Andric     bottom = fake_stack()->AddrIsInFakeStack(addr);
328*68d75effSDimitry Andric     CHECK(bottom);
329*68d75effSDimitry Andric     access->offset = addr - bottom;
330*68d75effSDimitry Andric     access->frame_pc = ((uptr*)bottom)[2];
331*68d75effSDimitry Andric     access->frame_descr = (const char *)((uptr*)bottom)[1];
332*68d75effSDimitry Andric     return true;
333*68d75effSDimitry Andric   }
334*68d75effSDimitry Andric   uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8);  // align addr.
335*68d75effSDimitry Andric   uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY);
336*68d75effSDimitry Andric   u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
337*68d75effSDimitry Andric   u8 *shadow_bottom = (u8*)MemToShadow(bottom);
338*68d75effSDimitry Andric 
339*68d75effSDimitry Andric   while (shadow_ptr >= shadow_bottom &&
340*68d75effSDimitry Andric          *shadow_ptr != kAsanStackLeftRedzoneMagic) {
341*68d75effSDimitry Andric     shadow_ptr--;
342*68d75effSDimitry Andric     mem_ptr -= SHADOW_GRANULARITY;
343*68d75effSDimitry Andric   }
344*68d75effSDimitry Andric 
345*68d75effSDimitry Andric   while (shadow_ptr >= shadow_bottom &&
346*68d75effSDimitry Andric          *shadow_ptr == kAsanStackLeftRedzoneMagic) {
347*68d75effSDimitry Andric     shadow_ptr--;
348*68d75effSDimitry Andric     mem_ptr -= SHADOW_GRANULARITY;
349*68d75effSDimitry Andric   }
350*68d75effSDimitry Andric 
351*68d75effSDimitry Andric   if (shadow_ptr < shadow_bottom) {
352*68d75effSDimitry Andric     return false;
353*68d75effSDimitry Andric   }
354*68d75effSDimitry Andric 
355*68d75effSDimitry Andric   uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY);
356*68d75effSDimitry Andric   CHECK(ptr[0] == kCurrentStackFrameMagic);
357*68d75effSDimitry Andric   access->offset = addr - (uptr)ptr;
358*68d75effSDimitry Andric   access->frame_pc = ptr[2];
359*68d75effSDimitry Andric   access->frame_descr = (const char*)ptr[1];
360*68d75effSDimitry Andric   return true;
361*68d75effSDimitry Andric }
362*68d75effSDimitry Andric 
363*68d75effSDimitry Andric uptr AsanThread::GetStackVariableShadowStart(uptr addr) {
364*68d75effSDimitry Andric   uptr bottom = 0;
365*68d75effSDimitry Andric   if (AddrIsInStack(addr)) {
366*68d75effSDimitry Andric     bottom = stack_bottom();
367*68d75effSDimitry Andric   } else if (has_fake_stack()) {
368*68d75effSDimitry Andric     bottom = fake_stack()->AddrIsInFakeStack(addr);
369*68d75effSDimitry Andric     CHECK(bottom);
370*68d75effSDimitry Andric   } else {
371*68d75effSDimitry Andric     return 0;
372*68d75effSDimitry Andric   }
373*68d75effSDimitry Andric 
374*68d75effSDimitry Andric   uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8);  // align addr.
375*68d75effSDimitry Andric   u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
376*68d75effSDimitry Andric   u8 *shadow_bottom = (u8*)MemToShadow(bottom);
377*68d75effSDimitry Andric 
378*68d75effSDimitry Andric   while (shadow_ptr >= shadow_bottom &&
379*68d75effSDimitry Andric          (*shadow_ptr != kAsanStackLeftRedzoneMagic &&
380*68d75effSDimitry Andric           *shadow_ptr != kAsanStackMidRedzoneMagic &&
381*68d75effSDimitry Andric           *shadow_ptr != kAsanStackRightRedzoneMagic))
382*68d75effSDimitry Andric     shadow_ptr--;
383*68d75effSDimitry Andric 
384*68d75effSDimitry Andric   return (uptr)shadow_ptr + 1;
385*68d75effSDimitry Andric }
386*68d75effSDimitry Andric 
387*68d75effSDimitry Andric bool AsanThread::AddrIsInStack(uptr addr) {
388*68d75effSDimitry Andric   const auto bounds = GetStackBounds();
389*68d75effSDimitry Andric   return addr >= bounds.bottom && addr < bounds.top;
390*68d75effSDimitry Andric }
391*68d75effSDimitry Andric 
392*68d75effSDimitry Andric static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
393*68d75effSDimitry Andric                                        void *addr) {
394*68d75effSDimitry Andric   AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
395*68d75effSDimitry Andric   AsanThread *t = tctx->thread;
396*68d75effSDimitry Andric   if (!t) return false;
397*68d75effSDimitry Andric   if (t->AddrIsInStack((uptr)addr)) return true;
398*68d75effSDimitry Andric   if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr))
399*68d75effSDimitry Andric     return true;
400*68d75effSDimitry Andric   return false;
401*68d75effSDimitry Andric }
402*68d75effSDimitry Andric 
403*68d75effSDimitry Andric AsanThread *GetCurrentThread() {
404*68d75effSDimitry Andric   if (SANITIZER_RTEMS && !asan_inited)
405*68d75effSDimitry Andric     return nullptr;
406*68d75effSDimitry Andric 
407*68d75effSDimitry Andric   AsanThreadContext *context =
408*68d75effSDimitry Andric       reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
409*68d75effSDimitry Andric   if (!context) {
410*68d75effSDimitry Andric     if (SANITIZER_ANDROID) {
411*68d75effSDimitry Andric       // On Android, libc constructor is called _after_ asan_init, and cleans up
412*68d75effSDimitry Andric       // TSD. Try to figure out if this is still the main thread by the stack
413*68d75effSDimitry Andric       // address. We are not entirely sure that we have correct main thread
414*68d75effSDimitry Andric       // limits, so only do this magic on Android, and only if the found thread
415*68d75effSDimitry Andric       // is the main thread.
416*68d75effSDimitry Andric       AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
417*68d75effSDimitry Andric       if (tctx && ThreadStackContainsAddress(tctx, &context)) {
418*68d75effSDimitry Andric         SetCurrentThread(tctx->thread);
419*68d75effSDimitry Andric         return tctx->thread;
420*68d75effSDimitry Andric       }
421*68d75effSDimitry Andric     }
422*68d75effSDimitry Andric     return nullptr;
423*68d75effSDimitry Andric   }
424*68d75effSDimitry Andric   return context->thread;
425*68d75effSDimitry Andric }
426*68d75effSDimitry Andric 
427*68d75effSDimitry Andric void SetCurrentThread(AsanThread *t) {
428*68d75effSDimitry Andric   CHECK(t->context());
429*68d75effSDimitry Andric   VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(),
430*68d75effSDimitry Andric           (void *)GetThreadSelf());
431*68d75effSDimitry Andric   // Make sure we do not reset the current AsanThread.
432*68d75effSDimitry Andric   CHECK_EQ(0, AsanTSDGet());
433*68d75effSDimitry Andric   AsanTSDSet(t->context());
434*68d75effSDimitry Andric   CHECK_EQ(t->context(), AsanTSDGet());
435*68d75effSDimitry Andric }
436*68d75effSDimitry Andric 
437*68d75effSDimitry Andric u32 GetCurrentTidOrInvalid() {
438*68d75effSDimitry Andric   AsanThread *t = GetCurrentThread();
439*68d75effSDimitry Andric   return t ? t->tid() : kInvalidTid;
440*68d75effSDimitry Andric }
441*68d75effSDimitry Andric 
442*68d75effSDimitry Andric AsanThread *FindThreadByStackAddress(uptr addr) {
443*68d75effSDimitry Andric   asanThreadRegistry().CheckLocked();
444*68d75effSDimitry Andric   AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
445*68d75effSDimitry Andric       asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
446*68d75effSDimitry Andric                                                    (void *)addr));
447*68d75effSDimitry Andric   return tctx ? tctx->thread : nullptr;
448*68d75effSDimitry Andric }
449*68d75effSDimitry Andric 
450*68d75effSDimitry Andric void EnsureMainThreadIDIsCorrect() {
451*68d75effSDimitry Andric   AsanThreadContext *context =
452*68d75effSDimitry Andric       reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
453*68d75effSDimitry Andric   if (context && (context->tid == 0))
454*68d75effSDimitry Andric     context->os_id = GetTid();
455*68d75effSDimitry Andric }
456*68d75effSDimitry Andric 
457*68d75effSDimitry Andric __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) {
458*68d75effSDimitry Andric   __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
459*68d75effSDimitry Andric       __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
460*68d75effSDimitry Andric   if (!context) return nullptr;
461*68d75effSDimitry Andric   return context->thread;
462*68d75effSDimitry Andric }
463*68d75effSDimitry Andric } // namespace __asan
464*68d75effSDimitry Andric 
465*68d75effSDimitry Andric // --- Implementation of LSan-specific functions --- {{{1
466*68d75effSDimitry Andric namespace __lsan {
467*68d75effSDimitry Andric bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
468*68d75effSDimitry Andric                            uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
469*68d75effSDimitry Andric                            uptr *cache_end, DTLS **dtls) {
470*68d75effSDimitry Andric   __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
471*68d75effSDimitry Andric   if (!t) return false;
472*68d75effSDimitry Andric   *stack_begin = t->stack_bottom();
473*68d75effSDimitry Andric   *stack_end = t->stack_top();
474*68d75effSDimitry Andric   *tls_begin = t->tls_begin();
475*68d75effSDimitry Andric   *tls_end = t->tls_end();
476*68d75effSDimitry Andric   // ASan doesn't keep allocator caches in TLS, so these are unused.
477*68d75effSDimitry Andric   *cache_begin = 0;
478*68d75effSDimitry Andric   *cache_end = 0;
479*68d75effSDimitry Andric   *dtls = t->dtls();
480*68d75effSDimitry Andric   return true;
481*68d75effSDimitry Andric }
482*68d75effSDimitry Andric 
483*68d75effSDimitry Andric void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
484*68d75effSDimitry Andric                             void *arg) {
485*68d75effSDimitry Andric   __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
486*68d75effSDimitry Andric   if (t && t->has_fake_stack())
487*68d75effSDimitry Andric     t->fake_stack()->ForEachFakeFrame(callback, arg);
488*68d75effSDimitry Andric }
489*68d75effSDimitry Andric 
490*68d75effSDimitry Andric void LockThreadRegistry() {
491*68d75effSDimitry Andric   __asan::asanThreadRegistry().Lock();
492*68d75effSDimitry Andric }
493*68d75effSDimitry Andric 
494*68d75effSDimitry Andric void UnlockThreadRegistry() {
495*68d75effSDimitry Andric   __asan::asanThreadRegistry().Unlock();
496*68d75effSDimitry Andric }
497*68d75effSDimitry Andric 
498*68d75effSDimitry Andric ThreadRegistry *GetThreadRegistryLocked() {
499*68d75effSDimitry Andric   __asan::asanThreadRegistry().CheckLocked();
500*68d75effSDimitry Andric   return &__asan::asanThreadRegistry();
501*68d75effSDimitry Andric }
502*68d75effSDimitry Andric 
503*68d75effSDimitry Andric void EnsureMainThreadIDIsCorrect() {
504*68d75effSDimitry Andric   __asan::EnsureMainThreadIDIsCorrect();
505*68d75effSDimitry Andric }
506*68d75effSDimitry Andric } // namespace __lsan
507*68d75effSDimitry Andric 
508*68d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1
509*68d75effSDimitry Andric using namespace __asan;
510*68d75effSDimitry Andric 
511*68d75effSDimitry Andric extern "C" {
512*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
513*68d75effSDimitry Andric void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom,
514*68d75effSDimitry Andric                                     uptr size) {
515*68d75effSDimitry Andric   AsanThread *t = GetCurrentThread();
516*68d75effSDimitry Andric   if (!t) {
517*68d75effSDimitry Andric     VReport(1, "__asan_start_switch_fiber called from unknown thread\n");
518*68d75effSDimitry Andric     return;
519*68d75effSDimitry Andric   }
520*68d75effSDimitry Andric   t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size);
521*68d75effSDimitry Andric }
522*68d75effSDimitry Andric 
523*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
524*68d75effSDimitry Andric void __sanitizer_finish_switch_fiber(void* fakestack,
525*68d75effSDimitry Andric                                      const void **bottom_old,
526*68d75effSDimitry Andric                                      uptr *size_old) {
527*68d75effSDimitry Andric   AsanThread *t = GetCurrentThread();
528*68d75effSDimitry Andric   if (!t) {
529*68d75effSDimitry Andric     VReport(1, "__asan_finish_switch_fiber called from unknown thread\n");
530*68d75effSDimitry Andric     return;
531*68d75effSDimitry Andric   }
532*68d75effSDimitry Andric   t->FinishSwitchFiber((FakeStack*)fakestack,
533*68d75effSDimitry Andric                        (uptr*)bottom_old,
534*68d75effSDimitry Andric                        (uptr*)size_old);
535*68d75effSDimitry Andric }
536*68d75effSDimitry Andric }
537