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