1 //===-- asan_thread_registry.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 // 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 #include "sanitizer_common/sanitizer_common.h" 20 21 namespace __asan { 22 23 static AsanThreadRegistry asan_thread_registry(LINKER_INITIALIZED); 24 25 AsanThreadRegistry &asanThreadRegistry() { 26 return asan_thread_registry; 27 } 28 29 AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x) 30 : main_thread_(x), 31 main_thread_summary_(x), 32 accumulated_stats_(x), 33 max_malloced_memory_(x), 34 mu_(x) { } 35 36 void AsanThreadRegistry::Init() { 37 AsanTSDInit(AsanThreadSummary::TSDDtor); 38 main_thread_.set_summary(&main_thread_summary_); 39 main_thread_summary_.set_thread(&main_thread_); 40 RegisterThread(&main_thread_); 41 SetCurrent(&main_thread_); 42 // At this point only one thread exists. 43 inited_ = true; 44 } 45 46 void AsanThreadRegistry::RegisterThread(AsanThread *thread) { 47 BlockingMutexLock lock(&mu_); 48 u32 tid = n_threads_; 49 n_threads_++; 50 CHECK(n_threads_ < kMaxNumberOfThreads); 51 52 AsanThreadSummary *summary = thread->summary(); 53 CHECK(summary != 0); 54 summary->set_tid(tid); 55 thread_summaries_[tid] = summary; 56 } 57 58 void AsanThreadRegistry::UnregisterThread(AsanThread *thread) { 59 BlockingMutexLock lock(&mu_); 60 FlushToAccumulatedStatsUnlocked(&thread->stats()); 61 AsanThreadSummary *summary = thread->summary(); 62 CHECK(summary); 63 summary->set_thread(0); 64 } 65 66 AsanThread *AsanThreadRegistry::GetMain() { 67 return &main_thread_; 68 } 69 70 AsanThread *AsanThreadRegistry::GetCurrent() { 71 AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet(); 72 if (!summary) { 73 #if ASAN_ANDROID 74 // On Android, libc constructor is called _after_ asan_init, and cleans up 75 // TSD. Try to figure out if this is still the main thread by the stack 76 // address. We are not entirely sure that we have correct main thread 77 // limits, so only do this magic on Android, and only if the found thread is 78 // the main thread. 79 AsanThread* thread = FindThreadByStackAddress((uptr)&summary); 80 if (thread && thread->tid() == 0) { 81 SetCurrent(thread); 82 return thread; 83 } 84 #endif 85 return 0; 86 } 87 return summary->thread(); 88 } 89 90 void AsanThreadRegistry::SetCurrent(AsanThread *t) { 91 CHECK(t->summary()); 92 if (flags()->verbosity >= 2) { 93 Report("SetCurrent: %p for thread %p\n", 94 t->summary(), (void*)GetThreadSelf()); 95 } 96 // Make sure we do not reset the current AsanThread. 97 CHECK(AsanTSDGet() == 0); 98 AsanTSDSet(t->summary()); 99 CHECK(AsanTSDGet() == t->summary()); 100 } 101 102 AsanStats &AsanThreadRegistry::GetCurrentThreadStats() { 103 AsanThread *t = GetCurrent(); 104 return (t) ? t->stats() : main_thread_.stats(); 105 } 106 107 void AsanThreadRegistry::GetAccumulatedStats(AsanStats *stats) { 108 BlockingMutexLock lock(&mu_); 109 UpdateAccumulatedStatsUnlocked(); 110 internal_memcpy(stats, &accumulated_stats_, sizeof(accumulated_stats_)); 111 } 112 113 uptr AsanThreadRegistry::GetCurrentAllocatedBytes() { 114 BlockingMutexLock lock(&mu_); 115 UpdateAccumulatedStatsUnlocked(); 116 uptr malloced = accumulated_stats_.malloced; 117 uptr freed = accumulated_stats_.freed; 118 // Return sane value if malloced < freed due to racy 119 // way we update accumulated stats. 120 return (malloced > freed) ? malloced - freed : 1; 121 } 122 123 uptr AsanThreadRegistry::GetHeapSize() { 124 BlockingMutexLock lock(&mu_); 125 UpdateAccumulatedStatsUnlocked(); 126 return accumulated_stats_.mmaped - accumulated_stats_.munmaped; 127 } 128 129 uptr AsanThreadRegistry::GetFreeBytes() { 130 BlockingMutexLock lock(&mu_); 131 UpdateAccumulatedStatsUnlocked(); 132 uptr total_free = accumulated_stats_.mmaped 133 - accumulated_stats_.munmaped 134 + accumulated_stats_.really_freed 135 + accumulated_stats_.really_freed_redzones; 136 uptr total_used = accumulated_stats_.malloced 137 + accumulated_stats_.malloced_redzones; 138 // Return sane value if total_free < total_used due to racy 139 // way we update accumulated stats. 140 return (total_free > total_used) ? total_free - total_used : 1; 141 } 142 143 // Return several stats counters with a single call to 144 // UpdateAccumulatedStatsUnlocked(). 145 void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats *malloc_stats) { 146 BlockingMutexLock lock(&mu_); 147 UpdateAccumulatedStatsUnlocked(); 148 malloc_stats->blocks_in_use = accumulated_stats_.mallocs; 149 malloc_stats->size_in_use = accumulated_stats_.malloced; 150 malloc_stats->max_size_in_use = max_malloced_memory_; 151 malloc_stats->size_allocated = accumulated_stats_.mmaped; 152 } 153 154 AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) { 155 CHECK(tid < n_threads_); 156 CHECK(thread_summaries_[tid]); 157 return thread_summaries_[tid]; 158 } 159 160 AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) { 161 BlockingMutexLock lock(&mu_); 162 for (u32 tid = 0; tid < n_threads_; tid++) { 163 AsanThread *t = thread_summaries_[tid]->thread(); 164 if (!t || !(t->fake_stack().StackSize())) continue; 165 if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) { 166 return t; 167 } 168 } 169 return 0; 170 } 171 172 void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() { 173 for (u32 tid = 0; tid < n_threads_; tid++) { 174 AsanThread *t = thread_summaries_[tid]->thread(); 175 if (t != 0) { 176 FlushToAccumulatedStatsUnlocked(&t->stats()); 177 } 178 } 179 // This is not very accurate: we may miss allocation peaks that happen 180 // between two updates of accumulated_stats_. For more accurate bookkeeping 181 // the maximum should be updated on every malloc(), which is unacceptable. 182 if (max_malloced_memory_ < accumulated_stats_.malloced) { 183 max_malloced_memory_ = accumulated_stats_.malloced; 184 } 185 } 186 187 void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) { 188 // AsanStats consists of variables of type uptr only. 189 uptr *dst = (uptr*)&accumulated_stats_; 190 uptr *src = (uptr*)stats; 191 uptr num_fields = sizeof(AsanStats) / sizeof(uptr); 192 for (uptr i = 0; i < num_fields; i++) { 193 dst[i] += src[i]; 194 src[i] = 0; 195 } 196 } 197 198 } // namespace __asan 199