• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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