diff options
Diffstat (limited to 'gcc-4.8/libsanitizer/asan/asan_thread_registry.cc')
-rw-r--r-- | gcc-4.8/libsanitizer/asan/asan_thread_registry.cc | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/gcc-4.8/libsanitizer/asan/asan_thread_registry.cc b/gcc-4.8/libsanitizer/asan/asan_thread_registry.cc new file mode 100644 index 000000000..8fda9b6ea --- /dev/null +++ b/gcc-4.8/libsanitizer/asan/asan_thread_registry.cc @@ -0,0 +1,196 @@ +//===-- asan_thread_registry.cc -------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// AsanThreadRegistry-related code. AsanThreadRegistry is a container +// for summaries of all created threads. +//===----------------------------------------------------------------------===// + +#include "asan_stack.h" +#include "asan_thread.h" +#include "asan_thread_registry.h" +#include "sanitizer_common/sanitizer_common.h" + +namespace __asan { + +static AsanThreadRegistry asan_thread_registry(LINKER_INITIALIZED); + +AsanThreadRegistry &asanThreadRegistry() { + return asan_thread_registry; +} + +AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x) + : main_thread_(x), + main_thread_summary_(x), + accumulated_stats_(x), + max_malloced_memory_(x), + mu_(x) { } + +void AsanThreadRegistry::Init() { + AsanTSDInit(AsanThreadSummary::TSDDtor); + main_thread_.set_summary(&main_thread_summary_); + main_thread_summary_.set_thread(&main_thread_); + RegisterThread(&main_thread_); + SetCurrent(&main_thread_); + // At this point only one thread exists. + inited_ = true; +} + +void AsanThreadRegistry::RegisterThread(AsanThread *thread) { + BlockingMutexLock lock(&mu_); + u32 tid = n_threads_; + n_threads_++; + CHECK(n_threads_ < kMaxNumberOfThreads); + + AsanThreadSummary *summary = thread->summary(); + CHECK(summary != 0); + summary->set_tid(tid); + thread_summaries_[tid] = summary; +} + +void AsanThreadRegistry::UnregisterThread(AsanThread *thread) { + BlockingMutexLock lock(&mu_); + FlushToAccumulatedStatsUnlocked(&thread->stats()); + AsanThreadSummary *summary = thread->summary(); + CHECK(summary); + summary->set_thread(0); +} + +AsanThread *AsanThreadRegistry::GetMain() { + return &main_thread_; +} + +AsanThread *AsanThreadRegistry::GetCurrent() { + AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet(); + if (!summary) { +#if ASAN_ANDROID + // On Android, libc constructor is called _after_ asan_init, and cleans up + // TSD. Try to figure out if this is still the main thread by the stack + // address. We are not entirely sure that we have correct main thread + // limits, so only do this magic on Android, and only if the found thread is + // the main thread. + AsanThread* thread = FindThreadByStackAddress((uptr)&summary); + if (thread && thread->tid() == 0) { + SetCurrent(thread); + return thread; + } +#endif + return 0; + } + return summary->thread(); +} + +void AsanThreadRegistry::SetCurrent(AsanThread *t) { + CHECK(t->summary()); + if (flags()->verbosity >= 2) { + Report("SetCurrent: %p for thread %p\n", + t->summary(), (void*)GetThreadSelf()); + } + // Make sure we do not reset the current AsanThread. + CHECK(AsanTSDGet() == 0); + AsanTSDSet(t->summary()); + CHECK(AsanTSDGet() == t->summary()); +} + +AsanStats &AsanThreadRegistry::GetCurrentThreadStats() { + AsanThread *t = GetCurrent(); + return (t) ? t->stats() : main_thread_.stats(); +} + +void AsanThreadRegistry::GetAccumulatedStats(AsanStats *stats) { + BlockingMutexLock lock(&mu_); + UpdateAccumulatedStatsUnlocked(); + internal_memcpy(stats, &accumulated_stats_, sizeof(accumulated_stats_)); +} + +uptr AsanThreadRegistry::GetCurrentAllocatedBytes() { + BlockingMutexLock lock(&mu_); + UpdateAccumulatedStatsUnlocked(); + uptr malloced = accumulated_stats_.malloced; + uptr freed = accumulated_stats_.freed; + // Return sane value if malloced < freed due to racy + // way we update accumulated stats. + return (malloced > freed) ? malloced - freed : 1; +} + +uptr AsanThreadRegistry::GetHeapSize() { + BlockingMutexLock lock(&mu_); + UpdateAccumulatedStatsUnlocked(); + return accumulated_stats_.mmaped - accumulated_stats_.munmaped; +} + +uptr AsanThreadRegistry::GetFreeBytes() { + BlockingMutexLock lock(&mu_); + UpdateAccumulatedStatsUnlocked(); + uptr total_free = accumulated_stats_.mmaped + - accumulated_stats_.munmaped + + accumulated_stats_.really_freed + + accumulated_stats_.really_freed_redzones; + uptr total_used = accumulated_stats_.malloced + + accumulated_stats_.malloced_redzones; + // Return sane value if total_free < total_used due to racy + // way we update accumulated stats. + return (total_free > total_used) ? total_free - total_used : 1; +} + +// Return several stats counters with a single call to +// UpdateAccumulatedStatsUnlocked(). +void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats *malloc_stats) { + BlockingMutexLock lock(&mu_); + UpdateAccumulatedStatsUnlocked(); + malloc_stats->blocks_in_use = accumulated_stats_.mallocs; + malloc_stats->size_in_use = accumulated_stats_.malloced; + malloc_stats->max_size_in_use = max_malloced_memory_; + malloc_stats->size_allocated = accumulated_stats_.mmaped; +} + +AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) { + CHECK(tid < n_threads_); + CHECK(thread_summaries_[tid]); + return thread_summaries_[tid]; +} + +AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) { + BlockingMutexLock lock(&mu_); + for (u32 tid = 0; tid < n_threads_; tid++) { + AsanThread *t = thread_summaries_[tid]->thread(); + if (!t || !(t->fake_stack().StackSize())) continue; + if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) { + return t; + } + } + return 0; +} + +void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() { + for (u32 tid = 0; tid < n_threads_; tid++) { + AsanThread *t = thread_summaries_[tid]->thread(); + if (t != 0) { + FlushToAccumulatedStatsUnlocked(&t->stats()); + } + } + // This is not very accurate: we may miss allocation peaks that happen + // between two updates of accumulated_stats_. For more accurate bookkeeping + // the maximum should be updated on every malloc(), which is unacceptable. + if (max_malloced_memory_ < accumulated_stats_.malloced) { + max_malloced_memory_ = accumulated_stats_.malloced; + } +} + +void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) { + // AsanStats consists of variables of type uptr only. + uptr *dst = (uptr*)&accumulated_stats_; + uptr *src = (uptr*)stats; + uptr num_fields = sizeof(AsanStats) / sizeof(uptr); + for (uptr i = 0; i < num_fields; i++) { + dst[i] += src[i]; + src[i] = 0; + } +} + +} // namespace __asan |