asan_thread.cc revision 195369bb7f59896487c4542716ca9c5d53975e78
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_mapping.h" 19#include "sanitizer_common/sanitizer_common.h" 20#include "sanitizer_common/sanitizer_placement_new.h" 21 22namespace __asan { 23 24// AsanThreadContext implementation. 25 26void AsanThreadContext::OnCreated(void *arg) { 27 CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg); 28 if (args->stack) { 29 internal_memcpy(&stack, args->stack, sizeof(stack)); 30 } 31 thread = args->thread; 32 thread->set_context(this); 33} 34 35void AsanThreadContext::OnFinished() { 36 // Drop the link to the AsanThread object. 37 thread = 0; 38} 39 40static char thread_registry_placeholder[sizeof(ThreadRegistry)]; 41static ThreadRegistry *asan_thread_registry; 42 43static ThreadContextBase *GetAsanThreadContext(u32 tid) { 44 void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext"); 45 return new(mem) AsanThreadContext(tid); 46} 47 48ThreadRegistry &asanThreadRegistry() { 49 static bool initialized; 50 // Don't worry about thread_safety - this should be called when there is 51 // a single thread. 52 if (!initialized) { 53 // Never reuse ASan threads: we store pointer to AsanThreadContext 54 // in TSD and can't reliably tell when no more TSD destructors will 55 // be called. It would be wrong to reuse AsanThreadContext for another 56 // thread before all TSD destructors will be called for it. 57 asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry( 58 GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads); 59 initialized = true; 60 } 61 return *asan_thread_registry; 62} 63 64AsanThreadContext *GetThreadContextByTidLocked(u32 tid) { 65 return static_cast<AsanThreadContext *>( 66 asanThreadRegistry().GetThreadLocked(tid)); 67} 68 69// AsanThread implementation. 70 71AsanThread *AsanThread::Create(thread_callback_t start_routine, 72 void *arg) { 73 uptr PageSize = GetPageSizeCached(); 74 uptr size = RoundUpTo(sizeof(AsanThread), PageSize); 75 AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__); 76 thread->start_routine_ = start_routine; 77 thread->arg_ = arg; 78 thread->context_ = 0; 79 80 return thread; 81} 82 83void AsanThread::TSDDtor(void *tsd) { 84 AsanThreadContext *context = (AsanThreadContext*)tsd; 85 if (flags()->verbosity >= 1) 86 Report("T%d TSDDtor\n", context->tid); 87 if (context->thread) 88 context->thread->Destroy(); 89} 90 91void AsanThread::Destroy() { 92 if (flags()->verbosity >= 1) { 93 Report("T%d exited\n", tid()); 94 } 95 96 asanThreadRegistry().FinishThread(tid()); 97 FlushToAccumulatedStats(&stats_); 98 // We also clear the shadow on thread destruction because 99 // some code may still be executing in later TSD destructors 100 // and we don't want it to have any poisoned stack. 101 ClearShadowForThreadStack(); 102 fake_stack().Cleanup(); 103 uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached()); 104 UnmapOrDie(this, size); 105} 106 107void AsanThread::Init() { 108 SetThreadStackTopAndBottom(); 109 CHECK(AddrIsInMem(stack_bottom_)); 110 CHECK(AddrIsInMem(stack_top_ - 1)); 111 ClearShadowForThreadStack(); 112 if (flags()->verbosity >= 1) { 113 int local = 0; 114 Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n", 115 tid(), (void*)stack_bottom_, (void*)stack_top_, 116 stack_top_ - stack_bottom_, &local); 117 } 118 fake_stack_.Init(stack_size()); 119 AsanPlatformThreadInit(); 120} 121 122thread_return_t AsanThread::ThreadStart(uptr os_id) { 123 Init(); 124 asanThreadRegistry().StartThread(tid(), os_id, 0); 125 if (flags()->use_sigaltstack) SetAlternateSignalStack(); 126 127 if (!start_routine_) { 128 // start_routine_ == 0 if we're on the main thread or on one of the 129 // OS X libdispatch worker threads. But nobody is supposed to call 130 // ThreadStart() for the worker threads. 131 CHECK(tid() == 0); 132 return 0; 133 } 134 135 thread_return_t res = start_routine_(arg_); 136 malloc_storage().CommitBack(); 137 if (flags()->use_sigaltstack) UnsetAlternateSignalStack(); 138 139 this->Destroy(); 140 141 return res; 142} 143 144void AsanThread::SetThreadStackTopAndBottom() { 145 GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_); 146 int local; 147 CHECK(AddrIsInStack((uptr)&local)); 148} 149 150void AsanThread::ClearShadowForThreadStack() { 151 PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); 152} 153 154const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) { 155 uptr bottom = 0; 156 if (AddrIsInStack(addr)) { 157 bottom = stack_bottom(); 158 } else { 159 bottom = fake_stack().AddrIsInFakeStack(addr); 160 CHECK(bottom); 161 *offset = addr - bottom; 162 return (const char *)((uptr*)bottom)[1]; 163 } 164 uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr. 165 u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); 166 u8 *shadow_bottom = (u8*)MemToShadow(bottom); 167 168 while (shadow_ptr >= shadow_bottom && 169 *shadow_ptr != kAsanStackLeftRedzoneMagic) { 170 shadow_ptr--; 171 } 172 173 while (shadow_ptr >= shadow_bottom && 174 *shadow_ptr == kAsanStackLeftRedzoneMagic) { 175 shadow_ptr--; 176 } 177 178 if (shadow_ptr < shadow_bottom) { 179 *offset = 0; 180 return "UNKNOWN"; 181 } 182 183 uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1)); 184 CHECK(ptr[0] == kCurrentStackFrameMagic); 185 *offset = addr - (uptr)ptr; 186 return (const char*)ptr[1]; 187} 188 189static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, 190 void *addr) { 191 AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base); 192 AsanThread *t = tctx->thread; 193 return (t && t->fake_stack().StackSize() && 194 (t->fake_stack().AddrIsInFakeStack((uptr)addr) || 195 t->AddrIsInStack((uptr)addr))); 196} 197 198AsanThread *GetCurrentThread() { 199 AsanThreadContext *context = (AsanThreadContext*)AsanTSDGet(); 200 if (!context) { 201 if (SANITIZER_ANDROID) { 202 // On Android, libc constructor is called _after_ asan_init, and cleans up 203 // TSD. Try to figure out if this is still the main thread by the stack 204 // address. We are not entirely sure that we have correct main thread 205 // limits, so only do this magic on Android, and only if the found thread 206 // is the main thread. 207 AsanThreadContext *tctx = GetThreadContextByTidLocked(0); 208 if (ThreadStackContainsAddress(tctx, &context)) { 209 SetCurrentThread(tctx->thread); 210 return tctx->thread; 211 } 212 } 213 return 0; 214 } 215 return context->thread; 216} 217 218void SetCurrentThread(AsanThread *t) { 219 CHECK(t->context()); 220 if (flags()->verbosity >= 2) { 221 Report("SetCurrentThread: %p for thread %p\n", 222 t->context(), (void*)GetThreadSelf()); 223 } 224 // Make sure we do not reset the current AsanThread. 225 CHECK_EQ(0, AsanTSDGet()); 226 AsanTSDSet(t->context()); 227 CHECK_EQ(t->context(), AsanTSDGet()); 228} 229 230u32 GetCurrentTidOrInvalid() { 231 AsanThread *t = GetCurrentThread(); 232 return t ? t->tid() : kInvalidTid; 233} 234 235AsanThread *FindThreadByStackAddress(uptr addr) { 236 asanThreadRegistry().CheckLocked(); 237 AsanThreadContext *tctx = static_cast<AsanThreadContext *>( 238 asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress, 239 (void *)addr)); 240 return tctx ? tctx->thread : 0; 241} 242 243} // namespace __asan 244