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