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       mu_(x) { }
     34 
     35 void AsanThreadRegistry::Init() {
     36   AsanTSDInit(AsanThreadSummary::TSDDtor);
     37   main_thread_.set_summary(&main_thread_summary_);
     38   main_thread_summary_.set_thread(&main_thread_);
     39   RegisterThread(&main_thread_);
     40   SetCurrent(&main_thread_);
     41   // At this point only one thread exists.
     42   inited_ = true;
     43 }
     44 
     45 void AsanThreadRegistry::RegisterThread(AsanThread *thread) {
     46   ScopedLock lock(&mu_);
     47   u32 tid = n_threads_;
     48   n_threads_++;
     49   CHECK(n_threads_ < kMaxNumberOfThreads);
     50 
     51   AsanThreadSummary *summary = thread->summary();
     52   CHECK(summary != 0);
     53   summary->set_tid(tid);
     54   thread_summaries_[tid] = summary;
     55 }
     56 
     57 void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
     58   ScopedLock lock(&mu_);
     59   FlushToAccumulatedStatsUnlocked(&thread->stats());
     60   AsanThreadSummary *summary = thread->summary();
     61   CHECK(summary);
     62   summary->set_thread(0);
     63 }
     64 
     65 AsanThread *AsanThreadRegistry::GetMain() {
     66   return &main_thread_;
     67 }
     68 
     69 AsanThread *AsanThreadRegistry::GetCurrent() {
     70   AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet();
     71   if (!summary) {
     72 #if ASAN_ANDROID
     73     // On Android, libc constructor is called _after_ asan_init, and cleans up
     74     // TSD. Try to figure out if this is still the main thread by the stack
     75     // address. We are not entirely sure that we have correct main thread
     76     // limits, so only do this magic on Android, and only if the found thread is
     77     // the main thread.
     78     AsanThread* thread = FindThreadByStackAddress((uptr)&summary);
     79     if (thread && thread->tid() == 0) {
     80       SetCurrent(thread);
     81       return thread;
     82     }
     83 #endif
     84     return 0;
     85   }
     86   return summary->thread();
     87 }
     88 
     89 void AsanThreadRegistry::SetCurrent(AsanThread *t) {
     90   CHECK(t->summary());
     91   if (flags()->verbosity >= 2) {
     92     Report("SetCurrent: %p for thread %p\n",
     93            t->summary(), (void*)GetThreadSelf());
     94   }
     95   // Make sure we do not reset the current AsanThread.
     96   CHECK(AsanTSDGet() == 0);
     97   AsanTSDSet(t->summary());
     98   CHECK(AsanTSDGet() == t->summary());
     99 }
    100 
    101 AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
    102   AsanThread *t = GetCurrent();
    103   return (t) ? t->stats() : main_thread_.stats();
    104 }
    105 
    106 AsanStats AsanThreadRegistry::GetAccumulatedStats() {
    107   ScopedLock lock(&mu_);
    108   UpdateAccumulatedStatsUnlocked();
    109   return accumulated_stats_;
    110 }
    111 
    112 uptr AsanThreadRegistry::GetCurrentAllocatedBytes() {
    113   ScopedLock lock(&mu_);
    114   UpdateAccumulatedStatsUnlocked();
    115   return accumulated_stats_.malloced - accumulated_stats_.freed;
    116 }
    117 
    118 uptr AsanThreadRegistry::GetHeapSize() {
    119   ScopedLock lock(&mu_);
    120   UpdateAccumulatedStatsUnlocked();
    121   return accumulated_stats_.mmaped;
    122 }
    123 
    124 uptr AsanThreadRegistry::GetFreeBytes() {
    125   ScopedLock lock(&mu_);
    126   UpdateAccumulatedStatsUnlocked();
    127   return accumulated_stats_.mmaped
    128          - accumulated_stats_.malloced
    129          - accumulated_stats_.malloced_redzones
    130          + accumulated_stats_.really_freed
    131          + accumulated_stats_.really_freed_redzones;
    132 }
    133 
    134 AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) {
    135   CHECK(tid < n_threads_);
    136   CHECK(thread_summaries_[tid]);
    137   return thread_summaries_[tid];
    138 }
    139 
    140 AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) {
    141   ScopedLock lock(&mu_);
    142   for (u32 tid = 0; tid < n_threads_; tid++) {
    143     AsanThread *t = thread_summaries_[tid]->thread();
    144     if (!t || !(t->fake_stack().StackSize())) continue;
    145     if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
    146       return t;
    147     }
    148   }
    149   return 0;
    150 }
    151 
    152 void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
    153   for (u32 tid = 0; tid < n_threads_; tid++) {
    154     AsanThread *t = thread_summaries_[tid]->thread();
    155     if (t != 0) {
    156       FlushToAccumulatedStatsUnlocked(&t->stats());
    157     }
    158   }
    159 }
    160 
    161 void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
    162   // AsanStats consists of variables of type uptr only.
    163   uptr *dst = (uptr*)&accumulated_stats_;
    164   uptr *src = (uptr*)stats;
    165   uptr num_fields = sizeof(AsanStats) / sizeof(uptr);
    166   for (uptr i = 0; i < num_fields; i++) {
    167     dst[i] += src[i];
    168     src[i] = 0;
    169   }
    170 }
    171 
    172 }  // namespace __asan
    173