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_stack.h"
     17 #include "asan_thread.h"
     18 #include "asan_thread_registry.h"
     19 #include "asan_mapping.h"
     20 #include "sanitizer_common/sanitizer_common.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(u32 parent_tid, thread_callback_t start_routine,
     30                                void *arg, StackTrace *stack) {
     31   uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
     32   AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
     33   thread->start_routine_ = start_routine;
     34   thread->arg_ = arg;
     35 
     36   const uptr kSummaryAllocSize = kPageSize;
     37   CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize);
     38   AsanThreadSummary *summary =
     39       (AsanThreadSummary*)MmapOrDie(kPageSize, "AsanThreadSummary");
     40   summary->Init(parent_tid, stack);
     41   summary->set_thread(thread);
     42   thread->set_summary(summary);
     43 
     44   return thread;
     45 }
     46 
     47 void AsanThreadSummary::TSDDtor(void *tsd) {
     48   AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
     49   if (flags()->verbosity >= 1) {
     50     Report("T%d TSDDtor\n", summary->tid());
     51   }
     52   if (summary->thread()) {
     53     summary->thread()->Destroy();
     54   }
     55 }
     56 
     57 void AsanThread::Destroy() {
     58   if (flags()->verbosity >= 1) {
     59     Report("T%d exited\n", tid());
     60   }
     61 
     62   asanThreadRegistry().UnregisterThread(this);
     63   CHECK(summary()->thread() == 0);
     64   // We also clear the shadow on thread destruction because
     65   // some code may still be executing in later TSD destructors
     66   // and we don't want it to have any poisoned stack.
     67   ClearShadowForThreadStack();
     68   fake_stack().Cleanup();
     69   uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
     70   UnmapOrDie(this, size);
     71 }
     72 
     73 void AsanThread::Init() {
     74   SetThreadStackTopAndBottom();
     75   CHECK(AddrIsInMem(stack_bottom_));
     76   CHECK(AddrIsInMem(stack_top_));
     77   ClearShadowForThreadStack();
     78   if (flags()->verbosity >= 1) {
     79     int local = 0;
     80     Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
     81            tid(), (void*)stack_bottom_, (void*)stack_top_,
     82            stack_top_ - stack_bottom_, &local);
     83   }
     84   fake_stack_.Init(stack_size());
     85   AsanPlatformThreadInit();
     86 }
     87 
     88 thread_return_t AsanThread::ThreadStart() {
     89   Init();
     90   if (flags()->use_sigaltstack) SetAlternateSignalStack();
     91 
     92   if (!start_routine_) {
     93     // start_routine_ == 0 if we're on the main thread or on one of the
     94     // OS X libdispatch worker threads. But nobody is supposed to call
     95     // ThreadStart() for the worker threads.
     96     CHECK(tid() == 0);
     97     return 0;
     98   }
     99 
    100   thread_return_t res = start_routine_(arg_);
    101   malloc_storage().CommitBack();
    102   if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
    103 
    104   this->Destroy();
    105 
    106   return res;
    107 }
    108 
    109 void AsanThread::SetThreadStackTopAndBottom() {
    110   GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
    111   int local;
    112   CHECK(AddrIsInStack((uptr)&local));
    113 }
    114 
    115 void AsanThread::ClearShadowForThreadStack() {
    116   PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
    117 }
    118 
    119 const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
    120   uptr bottom = 0;
    121   bool is_fake_stack = false;
    122   if (AddrIsInStack(addr)) {
    123     bottom = stack_bottom();
    124   } else {
    125     bottom = fake_stack().AddrIsInFakeStack(addr);
    126     CHECK(bottom);
    127     is_fake_stack = true;
    128   }
    129   uptr aligned_addr = addr & ~(__WORDSIZE/8 - 1);  // align addr.
    130   u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
    131   u8 *shadow_bottom = (u8*)MemToShadow(bottom);
    132 
    133   while (shadow_ptr >= shadow_bottom &&
    134       *shadow_ptr != kAsanStackLeftRedzoneMagic) {
    135     shadow_ptr--;
    136   }
    137 
    138   while (shadow_ptr >= shadow_bottom &&
    139       *shadow_ptr == kAsanStackLeftRedzoneMagic) {
    140     shadow_ptr--;
    141   }
    142 
    143   if (shadow_ptr < shadow_bottom) {
    144     *offset = 0;
    145     return "UNKNOWN";
    146   }
    147 
    148   uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
    149   CHECK((ptr[0] == kCurrentStackFrameMagic) ||
    150       (is_fake_stack && ptr[0] == kRetiredStackFrameMagic));
    151   *offset = addr - (uptr)ptr;
    152   return (const char*)ptr[1];
    153 }
    154 
    155 }  // namespace __asan
    156