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
asanThreadRegistry()24 AsanThreadRegistry &asanThreadRegistry() {
25 return asan_thread_registry;
26 }
27
AsanThreadRegistry(LinkerInitialized x)28 AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
29 : main_thread_(x),
30 main_thread_summary_(x),
31 accumulated_stats_(x),
32 mu_(x) { }
33
Init()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
RegisterThread(AsanThread * thread)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
UnregisterThread(AsanThread * thread)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
GetMain()64 AsanThread *AsanThreadRegistry::GetMain() {
65 return &main_thread_;
66 }
67
GetCurrent()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
SetCurrent(AsanThread * t)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
GetCurrentThreadStats()99 AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
100 AsanThread *t = GetCurrent();
101 return (t) ? t->stats() : main_thread_.stats();
102 }
103
GetAccumulatedStats()104 AsanStats AsanThreadRegistry::GetAccumulatedStats() {
105 ScopedLock lock(&mu_);
106 UpdateAccumulatedStatsUnlocked();
107 return accumulated_stats_;
108 }
109
GetCurrentAllocatedBytes()110 size_t AsanThreadRegistry::GetCurrentAllocatedBytes() {
111 ScopedLock lock(&mu_);
112 UpdateAccumulatedStatsUnlocked();
113 return accumulated_stats_.malloced - accumulated_stats_.freed;
114 }
115
GetHeapSize()116 size_t AsanThreadRegistry::GetHeapSize() {
117 ScopedLock lock(&mu_);
118 UpdateAccumulatedStatsUnlocked();
119 return accumulated_stats_.mmaped;
120 }
121
GetFreeBytes()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
FindByTid(int tid)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
FindThreadByStackAddress(uintptr_t addr)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
UpdateAccumulatedStatsUnlocked()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
FlushToAccumulatedStatsUnlocked(AsanStats * stats)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