Home | History | Annotate | Download | only in asan
      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 "lsan/lsan_common.h"
     23 
     24 namespace __asan {
     25 
     26 // AsanThreadContext implementation.
     27 
     28 void AsanThreadContext::OnCreated(void *arg) {
     29   CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
     30   if (args->stack) {
     31     internal_memcpy(&stack, args->stack, sizeof(stack));
     32   }
     33   thread = args->thread;
     34   thread->set_context(this);
     35 }
     36 
     37 void AsanThreadContext::OnFinished() {
     38   // Drop the link to the AsanThread object.
     39   thread = 0;
     40 }
     41 
     42 // MIPS requires aligned address
     43 static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
     44 static ThreadRegistry *asan_thread_registry;
     45 
     46 static ThreadContextBase *GetAsanThreadContext(u32 tid) {
     47   void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext");
     48   return new(mem) AsanThreadContext(tid);
     49 }
     50 
     51 ThreadRegistry &asanThreadRegistry() {
     52   static bool initialized;
     53   // Don't worry about thread_safety - this should be called when there is
     54   // a single thread.
     55   if (!initialized) {
     56     // Never reuse ASan threads: we store pointer to AsanThreadContext
     57     // in TSD and can't reliably tell when no more TSD destructors will
     58     // be called. It would be wrong to reuse AsanThreadContext for another
     59     // thread before all TSD destructors will be called for it.
     60     asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry(
     61         GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads);
     62     initialized = true;
     63   }
     64   return *asan_thread_registry;
     65 }
     66 
     67 AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
     68   return static_cast<AsanThreadContext *>(
     69       asanThreadRegistry().GetThreadLocked(tid));
     70 }
     71 
     72 // AsanThread implementation.
     73 
     74 AsanThread *AsanThread::Create(thread_callback_t start_routine,
     75                                void *arg) {
     76   uptr PageSize = GetPageSizeCached();
     77   uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
     78   AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
     79   thread->start_routine_ = start_routine;
     80   thread->arg_ = arg;
     81   thread->context_ = 0;
     82 
     83   return thread;
     84 }
     85 
     86 void AsanThread::TSDDtor(void *tsd) {
     87   AsanThreadContext *context = (AsanThreadContext*)tsd;
     88   if (flags()->verbosity >= 1)
     89     Report("T%d TSDDtor\n", context->tid);
     90   if (context->thread)
     91     context->thread->Destroy();
     92 }
     93 
     94 void AsanThread::Destroy() {
     95   if (flags()->verbosity >= 1) {
     96     Report("T%d exited\n", tid());
     97   }
     98 
     99   asanThreadRegistry().FinishThread(tid());
    100   FlushToAccumulatedStats(&stats_);
    101   // We also clear the shadow on thread destruction because
    102   // some code may still be executing in later TSD destructors
    103   // and we don't want it to have any poisoned stack.
    104   ClearShadowForThreadStackAndTLS();
    105   DeleteFakeStack();
    106   uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
    107   UnmapOrDie(this, size);
    108 }
    109 
    110 void AsanThread::Init() {
    111   SetThreadStackAndTls();
    112   CHECK(AddrIsInMem(stack_bottom_));
    113   CHECK(AddrIsInMem(stack_top_ - 1));
    114   ClearShadowForThreadStackAndTLS();
    115   if (flags()->verbosity >= 1) {
    116     int local = 0;
    117     Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
    118            tid(), (void*)stack_bottom_, (void*)stack_top_,
    119            stack_top_ - stack_bottom_, &local);
    120   }
    121   fake_stack_ = 0;  // Will be initialized lazily if needed.
    122   AsanPlatformThreadInit();
    123 }
    124 
    125 thread_return_t AsanThread::ThreadStart(uptr os_id) {
    126   Init();
    127   asanThreadRegistry().StartThread(tid(), os_id, 0);
    128   if (flags()->use_sigaltstack) SetAlternateSignalStack();
    129 
    130   if (!start_routine_) {
    131     // start_routine_ == 0 if we're on the main thread or on one of the
    132     // OS X libdispatch worker threads. But nobody is supposed to call
    133     // ThreadStart() for the worker threads.
    134     CHECK_EQ(tid(), 0);
    135     return 0;
    136   }
    137 
    138   thread_return_t res = start_routine_(arg_);
    139   malloc_storage().CommitBack();
    140   if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
    141 
    142   this->Destroy();
    143 
    144   return res;
    145 }
    146 
    147 void AsanThread::SetThreadStackAndTls() {
    148   uptr stack_size = 0, tls_size = 0;
    149   GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
    150                        &tls_size);
    151   stack_top_ = stack_bottom_ + stack_size;
    152   tls_end_ = tls_begin_ + tls_size;
    153 
    154   int local;
    155   CHECK(AddrIsInStack((uptr)&local));
    156 }
    157 
    158 void AsanThread::ClearShadowForThreadStackAndTLS() {
    159   PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
    160   if (tls_begin_ != tls_end_)
    161     PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
    162 }
    163 
    164 const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
    165                                            uptr *frame_pc) {
    166   uptr bottom = 0;
    167   if (AddrIsInStack(addr)) {
    168     bottom = stack_bottom();
    169   } else if (fake_stack()) {
    170     bottom = fake_stack()->AddrIsInFakeStack(addr);
    171     CHECK(bottom);
    172     *offset = addr - bottom;
    173     *frame_pc = ((uptr*)bottom)[2];
    174     return  (const char *)((uptr*)bottom)[1];
    175   }
    176   uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1);  // align addr.
    177   u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
    178   u8 *shadow_bottom = (u8*)MemToShadow(bottom);
    179 
    180   while (shadow_ptr >= shadow_bottom &&
    181          *shadow_ptr != kAsanStackLeftRedzoneMagic) {
    182     shadow_ptr--;
    183   }
    184 
    185   while (shadow_ptr >= shadow_bottom &&
    186          *shadow_ptr == kAsanStackLeftRedzoneMagic) {
    187     shadow_ptr--;
    188   }
    189 
    190   if (shadow_ptr < shadow_bottom) {
    191     *offset = 0;
    192     return "UNKNOWN";
    193   }
    194 
    195   uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
    196   CHECK(ptr[0] == kCurrentStackFrameMagic);
    197   *offset = addr - (uptr)ptr;
    198   *frame_pc = ptr[2];
    199   return (const char*)ptr[1];
    200 }
    201 
    202 static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
    203                                        void *addr) {
    204   AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
    205   AsanThread *t = tctx->thread;
    206   if (!t) return false;
    207   if (t->AddrIsInStack((uptr)addr)) return true;
    208   if (t->fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr))
    209     return true;
    210   return false;
    211 }
    212 
    213 AsanThread *GetCurrentThread() {
    214   AsanThreadContext *context =
    215       reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
    216   if (!context) {
    217     if (SANITIZER_ANDROID) {
    218       // On Android, libc constructor is called _after_ asan_init, and cleans up
    219       // TSD. Try to figure out if this is still the main thread by the stack
    220       // address. We are not entirely sure that we have correct main thread
    221       // limits, so only do this magic on Android, and only if the found thread
    222       // is the main thread.
    223       AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
    224       if (ThreadStackContainsAddress(tctx, &context)) {
    225         SetCurrentThread(tctx->thread);
    226         return tctx->thread;
    227       }
    228     }
    229     return 0;
    230   }
    231   return context->thread;
    232 }
    233 
    234 void SetCurrentThread(AsanThread *t) {
    235   CHECK(t->context());
    236   if (flags()->verbosity >= 2) {
    237     Report("SetCurrentThread: %p for thread %p\n",
    238            t->context(), (void*)GetThreadSelf());
    239   }
    240   // Make sure we do not reset the current AsanThread.
    241   CHECK_EQ(0, AsanTSDGet());
    242   AsanTSDSet(t->context());
    243   CHECK_EQ(t->context(), AsanTSDGet());
    244 }
    245 
    246 u32 GetCurrentTidOrInvalid() {
    247   AsanThread *t = GetCurrentThread();
    248   return t ? t->tid() : kInvalidTid;
    249 }
    250 
    251 AsanThread *FindThreadByStackAddress(uptr addr) {
    252   asanThreadRegistry().CheckLocked();
    253   AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
    254       asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
    255                                                    (void *)addr));
    256   return tctx ? tctx->thread : 0;
    257 }
    258 
    259 void EnsureMainThreadIDIsCorrect() {
    260   AsanThreadContext *context =
    261       reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
    262   if (context && (context->tid == 0))
    263     context->os_id = GetTid();
    264 }
    265 }  // namespace __asan
    266 
    267 // --- Implementation of LSan-specific functions --- {{{1
    268 namespace __lsan {
    269 bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
    270                            uptr *tls_begin, uptr *tls_end,
    271                            uptr *cache_begin, uptr *cache_end) {
    272   __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
    273       __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
    274   if (!context) return false;
    275   __asan::AsanThread *t = context->thread;
    276   if (!t) return false;
    277   *stack_begin = t->stack_bottom();
    278   *stack_end = t->stack_top();
    279   *tls_begin = t->tls_begin();
    280   *tls_end = t->tls_end();
    281   // ASan doesn't keep allocator caches in TLS, so these are unused.
    282   *cache_begin = 0;
    283   *cache_end = 0;
    284   return true;
    285 }
    286 
    287 void LockThreadRegistry() {
    288   __asan::asanThreadRegistry().Lock();
    289 }
    290 
    291 void UnlockThreadRegistry() {
    292   __asan::asanThreadRegistry().Unlock();
    293 }
    294 
    295 void EnsureMainThreadIDIsCorrect() {
    296   __asan::EnsureMainThreadIDIsCorrect();
    297 }
    298 }  // namespace __lsan
    299