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
asanThreadRegistry()25 AsanThreadRegistry &asanThreadRegistry() {
26 return asan_thread_registry;
27 }
28
AsanThreadRegistry(LinkerInitialized x)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
Init()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
RegisterThread(AsanThread * thread)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
UnregisterThread(AsanThread * thread)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
GetMain()66 AsanThread *AsanThreadRegistry::GetMain() {
67 return &main_thread_;
68 }
69
GetCurrent()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
SetCurrent(AsanThread * t)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
GetCurrentThreadStats()102 AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
103 AsanThread *t = GetCurrent();
104 return (t) ? t->stats() : main_thread_.stats();
105 }
106
GetAccumulatedStats(AsanStats * stats)107 void AsanThreadRegistry::GetAccumulatedStats(AsanStats *stats) {
108 BlockingMutexLock lock(&mu_);
109 UpdateAccumulatedStatsUnlocked();
110 internal_memcpy(stats, &accumulated_stats_, sizeof(accumulated_stats_));
111 }
112
GetCurrentAllocatedBytes()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
GetHeapSize()123 uptr AsanThreadRegistry::GetHeapSize() {
124 BlockingMutexLock lock(&mu_);
125 UpdateAccumulatedStatsUnlocked();
126 return accumulated_stats_.mmaped - accumulated_stats_.munmaped;
127 }
128
GetFreeBytes()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().
FillMallocStatistics(AsanMallocStats * malloc_stats)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
FindByTid(u32 tid)154 AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) {
155 CHECK(tid < n_threads_);
156 CHECK(thread_summaries_[tid]);
157 return thread_summaries_[tid];
158 }
159
FindThreadByStackAddress(uptr addr)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
UpdateAccumulatedStatsUnlocked()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
FlushToAccumulatedStatsUnlocked(AsanStats * stats)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