1 //===-- asan_thread_registry.cc ---------------------------------*- C++ -*-===// 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 // AsanThreadRegistry-related code. AsanThreadRegistry is a container 13 // for summaries of all created threads. 14 //===----------------------------------------------------------------------===// 15 16 #include "asan_stack.h" 17 #include "asan_thread.h" 18 #include "asan_thread_registry.h" 19 20 namespace __asan { 21 22 static AsanThreadRegistry asan_thread_registry(__asan::LINKER_INITIALIZED); 23 24 AsanThreadRegistry &asanThreadRegistry() { 25 return asan_thread_registry; 26 } 27 28 AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x) 29 : main_thread_(x), 30 main_thread_summary_(x), 31 accumulated_stats_(x), 32 mu_(x) { } 33 34 void AsanThreadRegistry::Init() { 35 AsanTSDInit(AsanThreadSummary::TSDDtor); 36 main_thread_.set_summary(&main_thread_summary_); 37 main_thread_summary_.set_thread(&main_thread_); 38 RegisterThread(&main_thread_); 39 SetCurrent(&main_thread_); 40 // At this point only one thread exists. 41 inited_ = true; 42 } 43 44 void AsanThreadRegistry::RegisterThread(AsanThread *thread) { 45 ScopedLock lock(&mu_); 46 int tid = n_threads_; 47 n_threads_++; 48 CHECK(n_threads_ < kMaxNumberOfThreads); 49 50 AsanThreadSummary *summary = thread->summary(); 51 CHECK(summary != NULL); 52 summary->set_tid(tid); 53 thread_summaries_[tid] = summary; 54 } 55 56 void AsanThreadRegistry::UnregisterThread(AsanThread *thread) { 57 ScopedLock lock(&mu_); 58 FlushToAccumulatedStatsUnlocked(&thread->stats()); 59 AsanThreadSummary *summary = thread->summary(); 60 CHECK(summary); 61 summary->set_thread(NULL); 62 } 63 64 AsanThread *AsanThreadRegistry::GetMain() { 65 return &main_thread_; 66 } 67 68 AsanThread *AsanThreadRegistry::GetCurrent() { 69 AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet(); 70 if (!summary) { 71 #ifdef ANDROID 72 // On Android, libc constructor is called _after_ asan_init, and cleans up 73 // TSD. Try to figure out if this is still the main thread by the stack 74 // address. We are not entirely sure that we have correct main thread 75 // limits, so only do this magic on Android, and only if the found thread is 76 // the main thread. 77 AsanThread* thread = FindThreadByStackAddress((uintptr_t)&summary); 78 if (thread && thread->tid() == 0) { 79 SetCurrent(thread); 80 return thread; 81 } 82 #endif 83 return 0; 84 } 85 return summary->thread(); 86 } 87 88 void AsanThreadRegistry::SetCurrent(AsanThread *t) { 89 CHECK(t->summary()); 90 if (FLAG_v >= 2) { 91 Report("SetCurrent: %p for thread %p\n", t->summary(), GetThreadSelf()); 92 } 93 // Make sure we do not reset the current AsanThread. 94 CHECK(AsanTSDGet() == 0); 95 AsanTSDSet(t->summary()); 96 CHECK(AsanTSDGet() == t->summary()); 97 } 98 99 AsanStats &AsanThreadRegistry::GetCurrentThreadStats() { 100 AsanThread *t = GetCurrent(); 101 return (t) ? t->stats() : main_thread_.stats(); 102 } 103 104 AsanStats AsanThreadRegistry::GetAccumulatedStats() { 105 ScopedLock lock(&mu_); 106 UpdateAccumulatedStatsUnlocked(); 107 return accumulated_stats_; 108 } 109 110 size_t AsanThreadRegistry::GetCurrentAllocatedBytes() { 111 ScopedLock lock(&mu_); 112 UpdateAccumulatedStatsUnlocked(); 113 return accumulated_stats_.malloced - accumulated_stats_.freed; 114 } 115 116 size_t AsanThreadRegistry::GetHeapSize() { 117 ScopedLock lock(&mu_); 118 UpdateAccumulatedStatsUnlocked(); 119 return accumulated_stats_.mmaped; 120 } 121 122 size_t AsanThreadRegistry::GetFreeBytes() { 123 ScopedLock lock(&mu_); 124 UpdateAccumulatedStatsUnlocked(); 125 return accumulated_stats_.mmaped 126 - accumulated_stats_.malloced 127 - accumulated_stats_.malloced_redzones 128 + accumulated_stats_.really_freed 129 + accumulated_stats_.really_freed_redzones; 130 } 131 132 AsanThreadSummary *AsanThreadRegistry::FindByTid(int tid) { 133 CHECK(tid >= 0); 134 CHECK(tid < n_threads_); 135 CHECK(thread_summaries_[tid]); 136 return thread_summaries_[tid]; 137 } 138 139 AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uintptr_t addr) { 140 ScopedLock lock(&mu_); 141 // Main thread (tid = 0) stack limits are pretty much guessed; for the other 142 // threads we ask libpthread, so their limits must be correct. 143 // Scanning the thread list backwards makes this function more reliable. 144 for (int tid = n_threads_ - 1; tid >= 0; tid--) { 145 AsanThread *t = thread_summaries_[tid]->thread(); 146 if (!t || !(t->fake_stack().StackSize())) continue; 147 if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) { 148 return t; 149 } 150 } 151 return 0; 152 } 153 154 void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() { 155 for (int tid = 0; tid < n_threads_; tid++) { 156 AsanThread *t = thread_summaries_[tid]->thread(); 157 if (t != NULL) { 158 FlushToAccumulatedStatsUnlocked(&t->stats()); 159 } 160 } 161 } 162 163 void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) { 164 // AsanStats consists of variables of type size_t only. 165 size_t *dst = (size_t*)&accumulated_stats_; 166 size_t *src = (size_t*)stats; 167 size_t num_fields = sizeof(AsanStats) / sizeof(size_t); 168 for (size_t i = 0; i < num_fields; i++) { 169 dst[i] += src[i]; 170 src[i] = 0; 171 } 172 } 173 174 } // namespace __asan 175