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