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