Home | History | Annotate | Download | only in asan
      1 //===-- asan_thread.cc ------------------------------------------*- C++ -*-===//
      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_procmaps.h"
     17 #include "asan_stack.h"
     18 #include "asan_thread.h"
     19 #include "asan_thread_registry.h"
     20 #include "asan_mapping.h"
     21 
     22 namespace __asan {
     23 
     24 AsanThread::AsanThread(LinkerInitialized x)
     25     : fake_stack_(x),
     26       malloc_storage_(x),
     27       stats_(x) { }
     28 
     29 AsanThread *AsanThread::Create(int parent_tid, thread_callback_t start_routine,
     30                                void *arg, AsanStackTrace *stack) {
     31   size_t size = RoundUpTo(sizeof(AsanThread), kPageSize);
     32   AsanThread *thread = (AsanThread*)AsanMmapSomewhereOrDie(size, __FUNCTION__);
     33   thread->start_routine_ = start_routine;
     34   thread->arg_ = arg;
     35 
     36   AsanThreadSummary *summary = new AsanThreadSummary(parent_tid, stack);
     37   summary->set_thread(thread);
     38   thread->set_summary(summary);
     39 
     40   return thread;
     41 }
     42 
     43 void AsanThreadSummary::TSDDtor(void *tsd) {
     44   AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
     45   if (FLAG_v >= 1) {
     46     Report("T%d TSDDtor\n", summary->tid());
     47   }
     48   if (summary->thread()) {
     49     summary->thread()->Destroy();
     50   }
     51 }
     52 
     53 void AsanThread::Destroy() {
     54   if (FLAG_v >= 1) {
     55     Report("T%d exited\n", tid());
     56   }
     57 
     58   asanThreadRegistry().UnregisterThread(this);
     59   CHECK(summary()->thread() == NULL);
     60   // We also clear the shadow on thread destruction because
     61   // some code may still be executing in later TSD destructors
     62   // and we don't want it to have any poisoned stack.
     63   ClearShadowForThreadStack();
     64   fake_stack().Cleanup();
     65   size_t size = RoundUpTo(sizeof(AsanThread), kPageSize);
     66   AsanUnmapOrDie(this, size);
     67 }
     68 
     69 void AsanThread::Init() {
     70   SetThreadStackTopAndBottom();
     71   CHECK(AddrIsInMem(stack_bottom_));
     72   CHECK(AddrIsInMem(stack_top_));
     73   ClearShadowForThreadStack();
     74   if (FLAG_v >= 1) {
     75     int local = 0;
     76     Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
     77            tid(), stack_bottom_, stack_top_,
     78            stack_top_ - stack_bottom_, &local);
     79   }
     80   fake_stack_.Init(stack_size());
     81 }
     82 
     83 thread_return_t AsanThread::ThreadStart() {
     84   Init();
     85   if (FLAG_use_sigaltstack) SetAlternateSignalStack();
     86 
     87   if (!start_routine_) {
     88     // start_routine_ == NULL if we're on the main thread or on one of the
     89     // OS X libdispatch worker threads. But nobody is supposed to call
     90     // ThreadStart() for the worker threads.
     91     CHECK(tid() == 0);
     92     return 0;
     93   }
     94 
     95   thread_return_t res = start_routine_(arg_);
     96   malloc_storage().CommitBack();
     97   if (FLAG_use_sigaltstack) UnsetAlternateSignalStack();
     98 
     99   this->Destroy();
    100 
    101   return res;
    102 }
    103 
    104 void AsanThread::ClearShadowForThreadStack() {
    105   PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
    106 }
    107 
    108 const char *AsanThread::GetFrameNameByAddr(uintptr_t addr, uintptr_t *offset) {
    109   uintptr_t bottom = 0;
    110   bool is_fake_stack = false;
    111   if (AddrIsInStack(addr)) {
    112     bottom = stack_bottom();
    113   } else {
    114     bottom = fake_stack().AddrIsInFakeStack(addr);
    115     CHECK(bottom);
    116     is_fake_stack = true;
    117   }
    118   uintptr_t aligned_addr = addr & ~(__WORDSIZE/8 - 1);  // align addr.
    119   uintptr_t *ptr = (uintptr_t*)aligned_addr;
    120   while (ptr >= (uintptr_t*)bottom) {
    121     if (ptr[0] == kCurrentStackFrameMagic ||
    122         (is_fake_stack && ptr[0] == kRetiredStackFrameMagic)) {
    123       *offset = addr - (uintptr_t)ptr;
    124       return (const char*)ptr[1];
    125     }
    126     ptr--;
    127   }
    128   *offset = 0;
    129   return "UNKNOWN";
    130 }
    131 
    132 }  // namespace __asan
    133