Home | History | Annotate | Download | only in asan
      1 //===-- asan_thread_registry.cc -------------------------------------------===//
      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 #include "sanitizer_common/sanitizer_common.h"
     20 
     21 namespace __asan {
     22 
     23 static AsanThreadRegistry asan_thread_registry(LINKER_INITIALIZED);
     24 
     25 AsanThreadRegistry &asanThreadRegistry() {
     26   return asan_thread_registry;
     27 }
     28 
     29 AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
     30     : main_thread_(x),
     31       main_thread_summary_(x),
     32       accumulated_stats_(x),
     33       max_malloced_memory_(x),
     34       mu_(x) { }
     35 
     36 void AsanThreadRegistry::Init() {
     37   AsanTSDInit(AsanThreadSummary::TSDDtor);
     38   main_thread_.set_summary(&main_thread_summary_);
     39   main_thread_summary_.set_thread(&main_thread_);
     40   RegisterThread(&main_thread_);
     41   SetCurrent(&main_thread_);
     42   // At this point only one thread exists.
     43   inited_ = true;
     44 }
     45 
     46 void AsanThreadRegistry::RegisterThread(AsanThread *thread) {
     47   BlockingMutexLock lock(&mu_);
     48   u32 tid = n_threads_;
     49   n_threads_++;
     50   CHECK(n_threads_ < kMaxNumberOfThreads);
     51 
     52   AsanThreadSummary *summary = thread->summary();
     53   CHECK(summary != 0);
     54   summary->set_tid(tid);
     55   thread_summaries_[tid] = summary;
     56 }
     57 
     58 void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
     59   BlockingMutexLock lock(&mu_);
     60   FlushToAccumulatedStatsUnlocked(&thread->stats());
     61   AsanThreadSummary *summary = thread->summary();
     62   CHECK(summary);
     63   summary->set_thread(0);
     64 }
     65 
     66 AsanThread *AsanThreadRegistry::GetMain() {
     67   return &main_thread_;
     68 }
     69 
     70 AsanThread *AsanThreadRegistry::GetCurrent() {
     71   AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet();
     72   if (!summary) {
     73 #if ASAN_ANDROID
     74     // On Android, libc constructor is called _after_ asan_init, and cleans up
     75     // TSD. Try to figure out if this is still the main thread by the stack
     76     // address. We are not entirely sure that we have correct main thread
     77     // limits, so only do this magic on Android, and only if the found thread is
     78     // the main thread.
     79     AsanThread* thread = FindThreadByStackAddress((uptr)&summary);
     80     if (thread && thread->tid() == 0) {
     81       SetCurrent(thread);
     82       return thread;
     83     }
     84 #endif
     85     return 0;
     86   }
     87   return summary->thread();
     88 }
     89 
     90 void AsanThreadRegistry::SetCurrent(AsanThread *t) {
     91   CHECK(t->summary());
     92   if (flags()->verbosity >= 2) {
     93     Report("SetCurrent: %p for thread %p\n",
     94            t->summary(), (void*)GetThreadSelf());
     95   }
     96   // Make sure we do not reset the current AsanThread.
     97   CHECK(AsanTSDGet() == 0);
     98   AsanTSDSet(t->summary());
     99   CHECK(AsanTSDGet() == t->summary());
    100 }
    101 
    102 AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
    103   AsanThread *t = GetCurrent();
    104   return (t) ? t->stats() : main_thread_.stats();
    105 }
    106 
    107 void AsanThreadRegistry::GetAccumulatedStats(AsanStats *stats) {
    108   BlockingMutexLock lock(&mu_);
    109   UpdateAccumulatedStatsUnlocked();
    110   internal_memcpy(stats, &accumulated_stats_, sizeof(accumulated_stats_));
    111 }
    112 
    113 uptr AsanThreadRegistry::GetCurrentAllocatedBytes() {
    114   BlockingMutexLock lock(&mu_);
    115   UpdateAccumulatedStatsUnlocked();
    116   uptr malloced = accumulated_stats_.malloced;
    117   uptr freed = accumulated_stats_.freed;
    118   // Return sane value if malloced < freed due to racy
    119   // way we update accumulated stats.
    120   return (malloced > freed) ? malloced - freed : 1;
    121 }
    122 
    123 uptr AsanThreadRegistry::GetHeapSize() {
    124   BlockingMutexLock lock(&mu_);
    125   UpdateAccumulatedStatsUnlocked();
    126   return accumulated_stats_.mmaped - accumulated_stats_.munmaped;
    127 }
    128 
    129 uptr AsanThreadRegistry::GetFreeBytes() {
    130   BlockingMutexLock lock(&mu_);
    131   UpdateAccumulatedStatsUnlocked();
    132   uptr total_free = accumulated_stats_.mmaped
    133                   - accumulated_stats_.munmaped
    134                   + accumulated_stats_.really_freed
    135                   + accumulated_stats_.really_freed_redzones;
    136   uptr total_used = accumulated_stats_.malloced
    137                   + accumulated_stats_.malloced_redzones;
    138   // Return sane value if total_free < total_used due to racy
    139   // way we update accumulated stats.
    140   return (total_free > total_used) ? total_free - total_used : 1;
    141 }
    142 
    143 // Return several stats counters with a single call to
    144 // UpdateAccumulatedStatsUnlocked().
    145 void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats *malloc_stats) {
    146   BlockingMutexLock lock(&mu_);
    147   UpdateAccumulatedStatsUnlocked();
    148   malloc_stats->blocks_in_use = accumulated_stats_.mallocs;
    149   malloc_stats->size_in_use = accumulated_stats_.malloced;
    150   malloc_stats->max_size_in_use = max_malloced_memory_;
    151   malloc_stats->size_allocated = accumulated_stats_.mmaped;
    152 }
    153 
    154 AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) {
    155   CHECK(tid < n_threads_);
    156   CHECK(thread_summaries_[tid]);
    157   return thread_summaries_[tid];
    158 }
    159 
    160 AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) {
    161   BlockingMutexLock lock(&mu_);
    162   for (u32 tid = 0; tid < n_threads_; tid++) {
    163     AsanThread *t = thread_summaries_[tid]->thread();
    164     if (!t || !(t->fake_stack().StackSize())) continue;
    165     if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
    166       return t;
    167     }
    168   }
    169   return 0;
    170 }
    171 
    172 void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
    173   for (u32 tid = 0; tid < n_threads_; tid++) {
    174     AsanThread *t = thread_summaries_[tid]->thread();
    175     if (t != 0) {
    176       FlushToAccumulatedStatsUnlocked(&t->stats());
    177     }
    178   }
    179   // This is not very accurate: we may miss allocation peaks that happen
    180   // between two updates of accumulated_stats_. For more accurate bookkeeping
    181   // the maximum should be updated on every malloc(), which is unacceptable.
    182   if (max_malloced_memory_ < accumulated_stats_.malloced) {
    183     max_malloced_memory_ = accumulated_stats_.malloced;
    184   }
    185 }
    186 
    187 void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
    188   // AsanStats consists of variables of type uptr only.
    189   uptr *dst = (uptr*)&accumulated_stats_;
    190   uptr *src = (uptr*)stats;
    191   uptr num_fields = sizeof(AsanStats) / sizeof(uptr);
    192   for (uptr i = 0; i < num_fields; i++) {
    193     dst[i] += src[i];
    194     src[i] = 0;
    195   }
    196 }
    197 
    198 }  // namespace __asan
    199