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 ScopedLock
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 ScopedLock
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 AsanStats
AsanThreadRegistry::GetAccumulatedStats() {
106 ScopedLock
lock(&mu_
);
107 UpdateAccumulatedStatsUnlocked();
108 return accumulated_stats_
;
111 uptr
AsanThreadRegistry::GetCurrentAllocatedBytes() {
112 ScopedLock
lock(&mu_
);
113 UpdateAccumulatedStatsUnlocked();
114 return accumulated_stats_
.malloced
- accumulated_stats_
.freed
;
117 uptr
AsanThreadRegistry::GetHeapSize() {
118 ScopedLock
lock(&mu_
);
119 UpdateAccumulatedStatsUnlocked();
120 return accumulated_stats_
.mmaped
;
123 uptr
AsanThreadRegistry::GetFreeBytes() {
124 ScopedLock
lock(&mu_
);
125 UpdateAccumulatedStatsUnlocked();
126 return accumulated_stats_
.mmaped
127 - accumulated_stats_
.malloced
128 - accumulated_stats_
.malloced_redzones
129 + accumulated_stats_
.really_freed
130 + accumulated_stats_
.really_freed_redzones
;
133 // Return several stats counters with a single call to
134 // UpdateAccumulatedStatsUnlocked().
135 void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats
*malloc_stats
) {
136 ScopedLock
lock(&mu_
);
137 UpdateAccumulatedStatsUnlocked();
138 malloc_stats
->blocks_in_use
= accumulated_stats_
.mallocs
;
139 malloc_stats
->size_in_use
= accumulated_stats_
.malloced
;
140 malloc_stats
->max_size_in_use
= max_malloced_memory_
;
141 malloc_stats
->size_allocated
= accumulated_stats_
.mmaped
;
144 AsanThreadSummary
*AsanThreadRegistry::FindByTid(u32 tid
) {
145 CHECK(tid
< n_threads_
);
146 CHECK(thread_summaries_
[tid
]);
147 return thread_summaries_
[tid
];
150 AsanThread
*AsanThreadRegistry::FindThreadByStackAddress(uptr addr
) {
151 ScopedLock
lock(&mu_
);
152 for (u32 tid
= 0; tid
< n_threads_
; tid
++) {
153 AsanThread
*t
= thread_summaries_
[tid
]->thread();
154 if (!t
|| !(t
->fake_stack().StackSize())) continue;
155 if (t
->fake_stack().AddrIsInFakeStack(addr
) || t
->AddrIsInStack(addr
)) {
162 void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
163 for (u32 tid
= 0; tid
< n_threads_
; tid
++) {
164 AsanThread
*t
= thread_summaries_
[tid
]->thread();
166 FlushToAccumulatedStatsUnlocked(&t
->stats());
169 // This is not very accurate: we may miss allocation peaks that happen
170 // between two updates of accumulated_stats_. For more accurate bookkeeping
171 // the maximum should be updated on every malloc(), which is unacceptable.
172 if (max_malloced_memory_
< accumulated_stats_
.malloced
) {
173 max_malloced_memory_
= accumulated_stats_
.malloced
;
177 void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats
*stats
) {
178 // AsanStats consists of variables of type uptr only.
179 uptr
*dst
= (uptr
*)&accumulated_stats_
;
180 uptr
*src
= (uptr
*)stats
;
181 uptr num_fields
= sizeof(AsanStats
) / sizeof(uptr
);
182 for (uptr i
= 0; i
< num_fields
; i
++) {
188 } // namespace __asan