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