1353944Sdim//===-- asan_thread.cpp ---------------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is a part of AddressSanitizer, an address sanity checker.
10353944Sdim//
11353944Sdim// Thread-related code.
12353944Sdim//===----------------------------------------------------------------------===//
13353944Sdim#include "asan_allocator.h"
14353944Sdim#include "asan_interceptors.h"
15353944Sdim#include "asan_poisoning.h"
16353944Sdim#include "asan_stack.h"
17353944Sdim#include "asan_thread.h"
18353944Sdim#include "asan_mapping.h"
19353944Sdim#include "sanitizer_common/sanitizer_common.h"
20353944Sdim#include "sanitizer_common/sanitizer_placement_new.h"
21353944Sdim#include "sanitizer_common/sanitizer_stackdepot.h"
22353944Sdim#include "sanitizer_common/sanitizer_tls_get_addr.h"
23353944Sdim#include "lsan/lsan_common.h"
24353944Sdim
25353944Sdimnamespace __asan {
26353944Sdim
27353944Sdim// AsanThreadContext implementation.
28353944Sdim
29353944Sdimvoid AsanThreadContext::OnCreated(void *arg) {
30353944Sdim  CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
31353944Sdim  if (args->stack)
32353944Sdim    stack_id = StackDepotPut(*args->stack);
33353944Sdim  thread = args->thread;
34353944Sdim  thread->set_context(this);
35353944Sdim}
36353944Sdim
37353944Sdimvoid AsanThreadContext::OnFinished() {
38353944Sdim  // Drop the link to the AsanThread object.
39353944Sdim  thread = nullptr;
40353944Sdim}
41353944Sdim
42353944Sdim// MIPS requires aligned address
43353944Sdimstatic ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
44353944Sdimstatic ThreadRegistry *asan_thread_registry;
45353944Sdim
46353944Sdimstatic BlockingMutex mu_for_thread_context(LINKER_INITIALIZED);
47353944Sdimstatic LowLevelAllocator allocator_for_thread_context;
48353944Sdim
49353944Sdimstatic ThreadContextBase *GetAsanThreadContext(u32 tid) {
50353944Sdim  BlockingMutexLock lock(&mu_for_thread_context);
51353944Sdim  return new(allocator_for_thread_context) AsanThreadContext(tid);
52353944Sdim}
53353944Sdim
54353944SdimThreadRegistry &asanThreadRegistry() {
55353944Sdim  static bool initialized;
56353944Sdim  // Don't worry about thread_safety - this should be called when there is
57353944Sdim  // a single thread.
58353944Sdim  if (!initialized) {
59353944Sdim    // Never reuse ASan threads: we store pointer to AsanThreadContext
60353944Sdim    // in TSD and can't reliably tell when no more TSD destructors will
61353944Sdim    // be called. It would be wrong to reuse AsanThreadContext for another
62353944Sdim    // thread before all TSD destructors will be called for it.
63353944Sdim    asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry(
64353944Sdim        GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads);
65353944Sdim    initialized = true;
66353944Sdim  }
67353944Sdim  return *asan_thread_registry;
68353944Sdim}
69353944Sdim
70353944SdimAsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
71353944Sdim  return static_cast<AsanThreadContext *>(
72353944Sdim      asanThreadRegistry().GetThreadLocked(tid));
73353944Sdim}
74353944Sdim
75353944Sdim// AsanThread implementation.
76353944Sdim
77353944SdimAsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
78353944Sdim                               u32 parent_tid, StackTrace *stack,
79353944Sdim                               bool detached) {
80353944Sdim  uptr PageSize = GetPageSizeCached();
81353944Sdim  uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
82353944Sdim  AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
83353944Sdim  thread->start_routine_ = start_routine;
84353944Sdim  thread->arg_ = arg;
85353944Sdim  AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
86353944Sdim  asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
87353944Sdim                                    parent_tid, &args);
88353944Sdim
89353944Sdim  return thread;
90353944Sdim}
91353944Sdim
92353944Sdimvoid AsanThread::TSDDtor(void *tsd) {
93353944Sdim  AsanThreadContext *context = (AsanThreadContext*)tsd;
94353944Sdim  VReport(1, "T%d TSDDtor\n", context->tid);
95353944Sdim  if (context->thread)
96353944Sdim    context->thread->Destroy();
97353944Sdim}
98353944Sdim
99353944Sdimvoid AsanThread::Destroy() {
100353944Sdim  int tid = this->tid();
101353944Sdim  VReport(1, "T%d exited\n", tid);
102353944Sdim
103353944Sdim  malloc_storage().CommitBack();
104353944Sdim  if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
105353944Sdim  asanThreadRegistry().FinishThread(tid);
106353944Sdim  FlushToDeadThreadStats(&stats_);
107353944Sdim  // We also clear the shadow on thread destruction because
108353944Sdim  // some code may still be executing in later TSD destructors
109353944Sdim  // and we don't want it to have any poisoned stack.
110353944Sdim  ClearShadowForThreadStackAndTLS();
111353944Sdim  DeleteFakeStack(tid);
112353944Sdim  uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
113353944Sdim  UnmapOrDie(this, size);
114353944Sdim  DTLS_Destroy();
115353944Sdim}
116353944Sdim
117353944Sdimvoid AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
118353944Sdim                                  uptr size) {
119353944Sdim  if (atomic_load(&stack_switching_, memory_order_relaxed)) {
120353944Sdim    Report("ERROR: starting fiber switch while in fiber switch\n");
121353944Sdim    Die();
122353944Sdim  }
123353944Sdim
124353944Sdim  next_stack_bottom_ = bottom;
125353944Sdim  next_stack_top_ = bottom + size;
126353944Sdim  atomic_store(&stack_switching_, 1, memory_order_release);
127353944Sdim
128353944Sdim  FakeStack *current_fake_stack = fake_stack_;
129353944Sdim  if (fake_stack_save)
130353944Sdim    *fake_stack_save = fake_stack_;
131353944Sdim  fake_stack_ = nullptr;
132353944Sdim  SetTLSFakeStack(nullptr);
133353944Sdim  // if fake_stack_save is null, the fiber will die, delete the fakestack
134353944Sdim  if (!fake_stack_save && current_fake_stack)
135353944Sdim    current_fake_stack->Destroy(this->tid());
136353944Sdim}
137353944Sdim
138353944Sdimvoid AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save,
139353944Sdim                                   uptr *bottom_old,
140353944Sdim                                   uptr *size_old) {
141353944Sdim  if (!atomic_load(&stack_switching_, memory_order_relaxed)) {
142353944Sdim    Report("ERROR: finishing a fiber switch that has not started\n");
143353944Sdim    Die();
144353944Sdim  }
145353944Sdim
146353944Sdim  if (fake_stack_save) {
147353944Sdim    SetTLSFakeStack(fake_stack_save);
148353944Sdim    fake_stack_ = fake_stack_save;
149353944Sdim  }
150353944Sdim
151353944Sdim  if (bottom_old)
152353944Sdim    *bottom_old = stack_bottom_;
153353944Sdim  if (size_old)
154353944Sdim    *size_old = stack_top_ - stack_bottom_;
155353944Sdim  stack_bottom_ = next_stack_bottom_;
156353944Sdim  stack_top_ = next_stack_top_;
157353944Sdim  atomic_store(&stack_switching_, 0, memory_order_release);
158353944Sdim  next_stack_top_ = 0;
159353944Sdim  next_stack_bottom_ = 0;
160353944Sdim}
161353944Sdim
162353944Sdiminline AsanThread::StackBounds AsanThread::GetStackBounds() const {
163353944Sdim  if (!atomic_load(&stack_switching_, memory_order_acquire)) {
164353944Sdim    // Make sure the stack bounds are fully initialized.
165353944Sdim    if (stack_bottom_ >= stack_top_) return {0, 0};
166353944Sdim    return {stack_bottom_, stack_top_};
167353944Sdim  }
168353944Sdim  char local;
169353944Sdim  const uptr cur_stack = (uptr)&local;
170353944Sdim  // Note: need to check next stack first, because FinishSwitchFiber
171353944Sdim  // may be in process of overwriting stack_top_/bottom_. But in such case
172353944Sdim  // we are already on the next stack.
173353944Sdim  if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_)
174353944Sdim    return {next_stack_bottom_, next_stack_top_};
175353944Sdim  return {stack_bottom_, stack_top_};
176353944Sdim}
177353944Sdim
178353944Sdimuptr AsanThread::stack_top() {
179353944Sdim  return GetStackBounds().top;
180353944Sdim}
181353944Sdim
182353944Sdimuptr AsanThread::stack_bottom() {
183353944Sdim  return GetStackBounds().bottom;
184353944Sdim}
185353944Sdim
186353944Sdimuptr AsanThread::stack_size() {
187353944Sdim  const auto bounds = GetStackBounds();
188353944Sdim  return bounds.top - bounds.bottom;
189353944Sdim}
190353944Sdim
191353944Sdim// We want to create the FakeStack lazyly on the first use, but not eralier
192353944Sdim// than the stack size is known and the procedure has to be async-signal safe.
193353944SdimFakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
194353944Sdim  uptr stack_size = this->stack_size();
195353944Sdim  if (stack_size == 0)  // stack_size is not yet available, don't use FakeStack.
196353944Sdim    return nullptr;
197353944Sdim  uptr old_val = 0;
198353944Sdim  // fake_stack_ has 3 states:
199353944Sdim  // 0   -- not initialized
200353944Sdim  // 1   -- being initialized
201353944Sdim  // ptr -- initialized
202353944Sdim  // This CAS checks if the state was 0 and if so changes it to state 1,
203353944Sdim  // if that was successful, it initializes the pointer.
204353944Sdim  if (atomic_compare_exchange_strong(
205353944Sdim      reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL,
206353944Sdim      memory_order_relaxed)) {
207353944Sdim    uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size));
208353944Sdim    CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
209353944Sdim    stack_size_log =
210353944Sdim        Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log));
211353944Sdim    stack_size_log =
212353944Sdim        Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
213353944Sdim    fake_stack_ = FakeStack::Create(stack_size_log);
214353944Sdim    SetTLSFakeStack(fake_stack_);
215353944Sdim    return fake_stack_;
216353944Sdim  }
217353944Sdim  return nullptr;
218353944Sdim}
219353944Sdim
220353944Sdimvoid AsanThread::Init(const InitOptions *options) {
221353944Sdim  next_stack_top_ = next_stack_bottom_ = 0;
222353944Sdim  atomic_store(&stack_switching_, false, memory_order_release);
223353944Sdim  CHECK_EQ(this->stack_size(), 0U);
224353944Sdim  SetThreadStackAndTls(options);
225353944Sdim  if (stack_top_ != stack_bottom_) {
226353944Sdim    CHECK_GT(this->stack_size(), 0U);
227353944Sdim    CHECK(AddrIsInMem(stack_bottom_));
228353944Sdim    CHECK(AddrIsInMem(stack_top_ - 1));
229353944Sdim  }
230353944Sdim  ClearShadowForThreadStackAndTLS();
231353944Sdim  fake_stack_ = nullptr;
232353944Sdim  if (__asan_option_detect_stack_use_after_return)
233353944Sdim    AsyncSignalSafeLazyInitFakeStack();
234353944Sdim  int local = 0;
235353944Sdim  VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
236353944Sdim          (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
237353944Sdim          &local);
238353944Sdim}
239353944Sdim
240353944Sdim// Fuchsia and RTEMS don't use ThreadStart.
241353944Sdim// asan_fuchsia.c/asan_rtems.c define CreateMainThread and
242353944Sdim// SetThreadStackAndTls.
243353944Sdim#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
244353944Sdim
245353944Sdimthread_return_t AsanThread::ThreadStart(
246353944Sdim    tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
247353944Sdim  Init();
248353944Sdim  asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
249353944Sdim  if (signal_thread_is_registered)
250353944Sdim    atomic_store(signal_thread_is_registered, 1, memory_order_release);
251353944Sdim
252353944Sdim  if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
253353944Sdim
254353944Sdim  if (!start_routine_) {
255353944Sdim    // start_routine_ == 0 if we're on the main thread or on one of the
256353944Sdim    // OS X libdispatch worker threads. But nobody is supposed to call
257353944Sdim    // ThreadStart() for the worker threads.
258353944Sdim    CHECK_EQ(tid(), 0);
259353944Sdim    return 0;
260353944Sdim  }
261353944Sdim
262353944Sdim  thread_return_t res = start_routine_(arg_);
263353944Sdim
264353944Sdim  // On POSIX systems we defer this to the TSD destructor. LSan will consider
265353944Sdim  // the thread's memory as non-live from the moment we call Destroy(), even
266353944Sdim  // though that memory might contain pointers to heap objects which will be
267353944Sdim  // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
268353944Sdim  // the TSD destructors have run might cause false positives in LSan.
269353944Sdim  if (!SANITIZER_POSIX)
270353944Sdim    this->Destroy();
271353944Sdim
272353944Sdim  return res;
273353944Sdim}
274353944Sdim
275353944SdimAsanThread *CreateMainThread() {
276353944Sdim  AsanThread *main_thread = AsanThread::Create(
277353944Sdim      /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
278353944Sdim      /* stack */ nullptr, /* detached */ true);
279353944Sdim  SetCurrentThread(main_thread);
280353944Sdim  main_thread->ThreadStart(internal_getpid(),
281353944Sdim                           /* signal_thread_is_registered */ nullptr);
282353944Sdim  return main_thread;
283353944Sdim}
284353944Sdim
285353944Sdim// This implementation doesn't use the argument, which is just passed down
286353944Sdim// from the caller of Init (which see, above).  It's only there to support
287353944Sdim// OS-specific implementations that need more information passed through.
288353944Sdimvoid AsanThread::SetThreadStackAndTls(const InitOptions *options) {
289353944Sdim  DCHECK_EQ(options, nullptr);
290353944Sdim  uptr tls_size = 0;
291353944Sdim  uptr stack_size = 0;
292353944Sdim  GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
293353944Sdim                       &tls_size);
294353944Sdim  stack_top_ = stack_bottom_ + stack_size;
295353944Sdim  tls_end_ = tls_begin_ + tls_size;
296353944Sdim  dtls_ = DTLS_Get();
297353944Sdim
298353944Sdim  if (stack_top_ != stack_bottom_) {
299353944Sdim    int local;
300353944Sdim    CHECK(AddrIsInStack((uptr)&local));
301353944Sdim  }
302353944Sdim}
303353944Sdim
304353944Sdim#endif  // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
305353944Sdim
306353944Sdimvoid AsanThread::ClearShadowForThreadStackAndTLS() {
307353944Sdim  if (stack_top_ != stack_bottom_)
308353944Sdim    PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
309353944Sdim  if (tls_begin_ != tls_end_) {
310353944Sdim    uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY);
311353944Sdim    uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY);
312353944Sdim    FastPoisonShadowPartialRightRedzone(tls_begin_aligned,
313353944Sdim                                        tls_end_ - tls_begin_aligned,
314353944Sdim                                        tls_end_aligned - tls_end_, 0);
315353944Sdim  }
316353944Sdim}
317353944Sdim
318353944Sdimbool AsanThread::GetStackFrameAccessByAddr(uptr addr,
319353944Sdim                                           StackFrameAccess *access) {
320353944Sdim  if (stack_top_ == stack_bottom_)
321353944Sdim    return false;
322353944Sdim
323353944Sdim  uptr bottom = 0;
324353944Sdim  if (AddrIsInStack(addr)) {
325353944Sdim    bottom = stack_bottom();
326353944Sdim  } else if (has_fake_stack()) {
327353944Sdim    bottom = fake_stack()->AddrIsInFakeStack(addr);
328353944Sdim    CHECK(bottom);
329353944Sdim    access->offset = addr - bottom;
330353944Sdim    access->frame_pc = ((uptr*)bottom)[2];
331353944Sdim    access->frame_descr = (const char *)((uptr*)bottom)[1];
332353944Sdim    return true;
333353944Sdim  }
334353944Sdim  uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8);  // align addr.
335353944Sdim  uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY);
336353944Sdim  u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
337353944Sdim  u8 *shadow_bottom = (u8*)MemToShadow(bottom);
338353944Sdim
339353944Sdim  while (shadow_ptr >= shadow_bottom &&
340353944Sdim         *shadow_ptr != kAsanStackLeftRedzoneMagic) {
341353944Sdim    shadow_ptr--;
342353944Sdim    mem_ptr -= SHADOW_GRANULARITY;
343353944Sdim  }
344353944Sdim
345353944Sdim  while (shadow_ptr >= shadow_bottom &&
346353944Sdim         *shadow_ptr == kAsanStackLeftRedzoneMagic) {
347353944Sdim    shadow_ptr--;
348353944Sdim    mem_ptr -= SHADOW_GRANULARITY;
349353944Sdim  }
350353944Sdim
351353944Sdim  if (shadow_ptr < shadow_bottom) {
352353944Sdim    return false;
353353944Sdim  }
354353944Sdim
355353944Sdim  uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY);
356353944Sdim  CHECK(ptr[0] == kCurrentStackFrameMagic);
357353944Sdim  access->offset = addr - (uptr)ptr;
358353944Sdim  access->frame_pc = ptr[2];
359353944Sdim  access->frame_descr = (const char*)ptr[1];
360353944Sdim  return true;
361353944Sdim}
362353944Sdim
363353944Sdimuptr AsanThread::GetStackVariableShadowStart(uptr addr) {
364353944Sdim  uptr bottom = 0;
365353944Sdim  if (AddrIsInStack(addr)) {
366353944Sdim    bottom = stack_bottom();
367353944Sdim  } else if (has_fake_stack()) {
368353944Sdim    bottom = fake_stack()->AddrIsInFakeStack(addr);
369353944Sdim    CHECK(bottom);
370353944Sdim  } else {
371353944Sdim    return 0;
372353944Sdim  }
373353944Sdim
374353944Sdim  uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8);  // align addr.
375353944Sdim  u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
376353944Sdim  u8 *shadow_bottom = (u8*)MemToShadow(bottom);
377353944Sdim
378353944Sdim  while (shadow_ptr >= shadow_bottom &&
379353944Sdim         (*shadow_ptr != kAsanStackLeftRedzoneMagic &&
380353944Sdim          *shadow_ptr != kAsanStackMidRedzoneMagic &&
381353944Sdim          *shadow_ptr != kAsanStackRightRedzoneMagic))
382353944Sdim    shadow_ptr--;
383353944Sdim
384353944Sdim  return (uptr)shadow_ptr + 1;
385353944Sdim}
386353944Sdim
387353944Sdimbool AsanThread::AddrIsInStack(uptr addr) {
388353944Sdim  const auto bounds = GetStackBounds();
389353944Sdim  return addr >= bounds.bottom && addr < bounds.top;
390353944Sdim}
391353944Sdim
392353944Sdimstatic bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
393353944Sdim                                       void *addr) {
394353944Sdim  AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
395353944Sdim  AsanThread *t = tctx->thread;
396353944Sdim  if (!t) return false;
397353944Sdim  if (t->AddrIsInStack((uptr)addr)) return true;
398353944Sdim  if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr))
399353944Sdim    return true;
400353944Sdim  return false;
401353944Sdim}
402353944Sdim
403353944SdimAsanThread *GetCurrentThread() {
404353944Sdim  if (SANITIZER_RTEMS && !asan_inited)
405353944Sdim    return nullptr;
406353944Sdim
407353944Sdim  AsanThreadContext *context =
408353944Sdim      reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
409353944Sdim  if (!context) {
410353944Sdim    if (SANITIZER_ANDROID) {
411353944Sdim      // On Android, libc constructor is called _after_ asan_init, and cleans up
412353944Sdim      // TSD. Try to figure out if this is still the main thread by the stack
413353944Sdim      // address. We are not entirely sure that we have correct main thread
414353944Sdim      // limits, so only do this magic on Android, and only if the found thread
415353944Sdim      // is the main thread.
416353944Sdim      AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
417353944Sdim      if (tctx && ThreadStackContainsAddress(tctx, &context)) {
418353944Sdim        SetCurrentThread(tctx->thread);
419353944Sdim        return tctx->thread;
420353944Sdim      }
421353944Sdim    }
422353944Sdim    return nullptr;
423353944Sdim  }
424353944Sdim  return context->thread;
425353944Sdim}
426353944Sdim
427353944Sdimvoid SetCurrentThread(AsanThread *t) {
428353944Sdim  CHECK(t->context());
429353944Sdim  VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(),
430353944Sdim          (void *)GetThreadSelf());
431353944Sdim  // Make sure we do not reset the current AsanThread.
432353944Sdim  CHECK_EQ(0, AsanTSDGet());
433353944Sdim  AsanTSDSet(t->context());
434353944Sdim  CHECK_EQ(t->context(), AsanTSDGet());
435353944Sdim}
436353944Sdim
437353944Sdimu32 GetCurrentTidOrInvalid() {
438353944Sdim  AsanThread *t = GetCurrentThread();
439353944Sdim  return t ? t->tid() : kInvalidTid;
440353944Sdim}
441353944Sdim
442353944SdimAsanThread *FindThreadByStackAddress(uptr addr) {
443353944Sdim  asanThreadRegistry().CheckLocked();
444353944Sdim  AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
445353944Sdim      asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
446353944Sdim                                                   (void *)addr));
447353944Sdim  return tctx ? tctx->thread : nullptr;
448353944Sdim}
449353944Sdim
450353944Sdimvoid EnsureMainThreadIDIsCorrect() {
451353944Sdim  AsanThreadContext *context =
452353944Sdim      reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
453353944Sdim  if (context && (context->tid == 0))
454353944Sdim    context->os_id = GetTid();
455353944Sdim}
456353944Sdim
457353944Sdim__asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) {
458353944Sdim  __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
459353944Sdim      __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
460353944Sdim  if (!context) return nullptr;
461353944Sdim  return context->thread;
462353944Sdim}
463353944Sdim} // namespace __asan
464353944Sdim
465353944Sdim// --- Implementation of LSan-specific functions --- {{{1
466353944Sdimnamespace __lsan {
467353944Sdimbool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
468353944Sdim                           uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
469353944Sdim                           uptr *cache_end, DTLS **dtls) {
470353944Sdim  __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
471353944Sdim  if (!t) return false;
472353944Sdim  *stack_begin = t->stack_bottom();
473353944Sdim  *stack_end = t->stack_top();
474353944Sdim  *tls_begin = t->tls_begin();
475353944Sdim  *tls_end = t->tls_end();
476353944Sdim  // ASan doesn't keep allocator caches in TLS, so these are unused.
477353944Sdim  *cache_begin = 0;
478353944Sdim  *cache_end = 0;
479353944Sdim  *dtls = t->dtls();
480353944Sdim  return true;
481353944Sdim}
482353944Sdim
483353944Sdimvoid ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
484353944Sdim                            void *arg) {
485353944Sdim  __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
486353944Sdim  if (t && t->has_fake_stack())
487353944Sdim    t->fake_stack()->ForEachFakeFrame(callback, arg);
488353944Sdim}
489353944Sdim
490353944Sdimvoid LockThreadRegistry() {
491353944Sdim  __asan::asanThreadRegistry().Lock();
492353944Sdim}
493353944Sdim
494353944Sdimvoid UnlockThreadRegistry() {
495353944Sdim  __asan::asanThreadRegistry().Unlock();
496353944Sdim}
497353944Sdim
498353944SdimThreadRegistry *GetThreadRegistryLocked() {
499353944Sdim  __asan::asanThreadRegistry().CheckLocked();
500353944Sdim  return &__asan::asanThreadRegistry();
501353944Sdim}
502353944Sdim
503353944Sdimvoid EnsureMainThreadIDIsCorrect() {
504353944Sdim  __asan::EnsureMainThreadIDIsCorrect();
505353944Sdim}
506353944Sdim} // namespace __lsan
507353944Sdim
508353944Sdim// ---------------------- Interface ---------------- {{{1
509353944Sdimusing namespace __asan;
510353944Sdim
511353944Sdimextern "C" {
512353944SdimSANITIZER_INTERFACE_ATTRIBUTE
513353944Sdimvoid __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom,
514353944Sdim                                    uptr size) {
515353944Sdim  AsanThread *t = GetCurrentThread();
516353944Sdim  if (!t) {
517353944Sdim    VReport(1, "__asan_start_switch_fiber called from unknown thread\n");
518353944Sdim    return;
519353944Sdim  }
520353944Sdim  t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size);
521353944Sdim}
522353944Sdim
523353944SdimSANITIZER_INTERFACE_ATTRIBUTE
524353944Sdimvoid __sanitizer_finish_switch_fiber(void* fakestack,
525353944Sdim                                     const void **bottom_old,
526353944Sdim                                     uptr *size_old) {
527353944Sdim  AsanThread *t = GetCurrentThread();
528353944Sdim  if (!t) {
529353944Sdim    VReport(1, "__asan_finish_switch_fiber called from unknown thread\n");
530353944Sdim    return;
531353944Sdim  }
532353944Sdim  t->FinishSwitchFiber((FakeStack*)fakestack,
533353944Sdim                       (uptr*)bottom_old,
534353944Sdim                       (uptr*)size_old);
535353944Sdim}
536353944Sdim}
537