1 //===-- asan_thread_registry.cc -------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of AddressSanitizer, an address sanity checker.
10 // AsanThreadRegistry-related code. AsanThreadRegistry is a container
11 // for summaries of all created threads.
12 //===----------------------------------------------------------------------===//
14 #include "asan_stack.h"
15 #include "asan_thread.h"
16 #include "asan_thread_registry.h"
17 #include "sanitizer_common/sanitizer_common.h"
21 static AsanThreadRegistry
asan_thread_registry(LINKER_INITIALIZED
);
23 AsanThreadRegistry
&asanThreadRegistry() {
24 return asan_thread_registry
;
27 AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x
)
29 main_thread_summary_(x
),
30 accumulated_stats_(x
),
31 max_malloced_memory_(x
),
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.
44 void AsanThreadRegistry::RegisterThread(AsanThread
*thread
) {
45 BlockingMutexLock
lock(&mu_
);
48 CHECK(n_threads_
< kMaxNumberOfThreads
);
50 AsanThreadSummary
*summary
= thread
->summary();
52 summary
->set_tid(tid
);
53 thread_summaries_
[tid
] = summary
;
56 void AsanThreadRegistry::UnregisterThread(AsanThread
*thread
) {
57 BlockingMutexLock
lock(&mu_
);
58 FlushToAccumulatedStatsUnlocked(&thread
->stats());
59 AsanThreadSummary
*summary
= thread
->summary();
61 summary
->set_thread(0);
64 AsanThread
*AsanThreadRegistry::GetMain() {
68 AsanThread
*AsanThreadRegistry::GetCurrent() {
69 AsanThreadSummary
*summary
= (AsanThreadSummary
*)AsanTSDGet();
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
77 AsanThread
* thread
= FindThreadByStackAddress((uptr
)&summary
);
78 if (thread
&& thread
->tid() == 0) {
85 return summary
->thread();
88 void AsanThreadRegistry::SetCurrent(AsanThread
*t
) {
90 if (flags()->verbosity
>= 2) {
91 Report("SetCurrent: %p for thread %p\n",
92 t
->summary(), (void*)GetThreadSelf());
94 // Make sure we do not reset the current AsanThread.
95 CHECK(AsanTSDGet() == 0);
96 AsanTSDSet(t
->summary());
97 CHECK(AsanTSDGet() == t
->summary());
100 AsanStats
&AsanThreadRegistry::GetCurrentThreadStats() {
101 AsanThread
*t
= GetCurrent();
102 return (t
) ? t
->stats() : main_thread_
.stats();
105 void AsanThreadRegistry::GetAccumulatedStats(AsanStats
*stats
) {
106 BlockingMutexLock
lock(&mu_
);
107 UpdateAccumulatedStatsUnlocked();
108 internal_memcpy(stats
, &accumulated_stats_
, sizeof(accumulated_stats_
));
111 uptr
AsanThreadRegistry::GetCurrentAllocatedBytes() {
112 BlockingMutexLock
lock(&mu_
);
113 UpdateAccumulatedStatsUnlocked();
114 uptr malloced
= accumulated_stats_
.malloced
;
115 uptr freed
= accumulated_stats_
.freed
;
116 // Return sane value if malloced < freed due to racy
117 // way we update accumulated stats.
118 return (malloced
> freed
) ? malloced
- freed
: 1;
121 uptr
AsanThreadRegistry::GetHeapSize() {
122 BlockingMutexLock
lock(&mu_
);
123 UpdateAccumulatedStatsUnlocked();
124 return accumulated_stats_
.mmaped
- accumulated_stats_
.munmaped
;
127 uptr
AsanThreadRegistry::GetFreeBytes() {
128 BlockingMutexLock
lock(&mu_
);
129 UpdateAccumulatedStatsUnlocked();
130 uptr total_free
= accumulated_stats_
.mmaped
131 - accumulated_stats_
.munmaped
132 + accumulated_stats_
.really_freed
133 + accumulated_stats_
.really_freed_redzones
;
134 uptr total_used
= accumulated_stats_
.malloced
135 + accumulated_stats_
.malloced_redzones
;
136 // Return sane value if total_free < total_used due to racy
137 // way we update accumulated stats.
138 return (total_free
> total_used
) ? total_free
- total_used
: 1;
141 // Return several stats counters with a single call to
142 // UpdateAccumulatedStatsUnlocked().
143 void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats
*malloc_stats
) {
144 BlockingMutexLock
lock(&mu_
);
145 UpdateAccumulatedStatsUnlocked();
146 malloc_stats
->blocks_in_use
= accumulated_stats_
.mallocs
;
147 malloc_stats
->size_in_use
= accumulated_stats_
.malloced
;
148 malloc_stats
->max_size_in_use
= max_malloced_memory_
;
149 malloc_stats
->size_allocated
= accumulated_stats_
.mmaped
;
152 AsanThreadSummary
*AsanThreadRegistry::FindByTid(u32 tid
) {
153 CHECK(tid
< n_threads_
);
154 CHECK(thread_summaries_
[tid
]);
155 return thread_summaries_
[tid
];
158 AsanThread
*AsanThreadRegistry::FindThreadByStackAddress(uptr addr
) {
159 BlockingMutexLock
lock(&mu_
);
160 for (u32 tid
= 0; tid
< n_threads_
; tid
++) {
161 AsanThread
*t
= thread_summaries_
[tid
]->thread();
162 if (!t
|| !(t
->fake_stack().StackSize())) continue;
163 if (t
->fake_stack().AddrIsInFakeStack(addr
) || t
->AddrIsInStack(addr
)) {
170 void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
171 for (u32 tid
= 0; tid
< n_threads_
; tid
++) {
172 AsanThread
*t
= thread_summaries_
[tid
]->thread();
174 FlushToAccumulatedStatsUnlocked(&t
->stats());
177 // This is not very accurate: we may miss allocation peaks that happen
178 // between two updates of accumulated_stats_. For more accurate bookkeeping
179 // the maximum should be updated on every malloc(), which is unacceptable.
180 if (max_malloced_memory_
< accumulated_stats_
.malloced
) {
181 max_malloced_memory_
= accumulated_stats_
.malloced
;
185 void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats
*stats
) {
186 // AsanStats consists of variables of type uptr only.
187 uptr
*dst
= (uptr
*)&accumulated_stats_
;
188 uptr
*src
= (uptr
*)stats
;
189 uptr num_fields
= sizeof(AsanStats
) / sizeof(uptr
);
190 for (uptr i
= 0; i
< num_fields
; i
++) {
196 } // namespace __asan