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