Home | History | Annotate | Download | only in asan
      1 //===-- asan_thread_registry.cc ---------------------------------*- C++ -*-===//
      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 
     20 namespace __asan {
     21 
     22 static AsanThreadRegistry asan_thread_registry(__asan::LINKER_INITIALIZED);
     23 
     24 AsanThreadRegistry &asanThreadRegistry() {
     25   return asan_thread_registry;
     26 }
     27 
     28 AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
     29     : main_thread_(x),
     30       main_thread_summary_(x),
     31       accumulated_stats_(x),
     32       mu_(x) { }
     33 
     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.
     41   inited_ = true;
     42 }
     43 
     44 void AsanThreadRegistry::RegisterThread(AsanThread *thread) {
     45   ScopedLock lock(&mu_);
     46   int tid = n_threads_;
     47   n_threads_++;
     48   CHECK(n_threads_ < kMaxNumberOfThreads);
     49 
     50   AsanThreadSummary *summary = thread->summary();
     51   CHECK(summary != NULL);
     52   summary->set_tid(tid);
     53   thread_summaries_[tid] = summary;
     54 }
     55 
     56 void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
     57   ScopedLock lock(&mu_);
     58   FlushToAccumulatedStatsUnlocked(&thread->stats());
     59   AsanThreadSummary *summary = thread->summary();
     60   CHECK(summary);
     61   summary->set_thread(NULL);
     62 }
     63 
     64 AsanThread *AsanThreadRegistry::GetMain() {
     65   return &main_thread_;
     66 }
     67 
     68 AsanThread *AsanThreadRegistry::GetCurrent() {
     69   AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet();
     70   if (!summary) {
     71 #ifdef ANDROID
     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
     76     // the main thread.
     77     AsanThread* thread = FindThreadByStackAddress((uintptr_t)&summary);
     78     if (thread && thread->tid() == 0) {
     79       SetCurrent(thread);
     80       return thread;
     81     }
     82 #endif
     83     return 0;
     84   }
     85   return summary->thread();
     86 }
     87 
     88 void AsanThreadRegistry::SetCurrent(AsanThread *t) {
     89   CHECK(t->summary());
     90   if (FLAG_v >= 2) {
     91     Report("SetCurrent: %p for thread %p\n", t->summary(), GetThreadSelf());
     92   }
     93   // Make sure we do not reset the current AsanThread.
     94   CHECK(AsanTSDGet() == 0);
     95   AsanTSDSet(t->summary());
     96   CHECK(AsanTSDGet() == t->summary());
     97 }
     98 
     99 AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
    100   AsanThread *t = GetCurrent();
    101   return (t) ? t->stats() : main_thread_.stats();
    102 }
    103 
    104 AsanStats AsanThreadRegistry::GetAccumulatedStats() {
    105   ScopedLock lock(&mu_);
    106   UpdateAccumulatedStatsUnlocked();
    107   return accumulated_stats_;
    108 }
    109 
    110 size_t AsanThreadRegistry::GetCurrentAllocatedBytes() {
    111   ScopedLock lock(&mu_);
    112   UpdateAccumulatedStatsUnlocked();
    113   return accumulated_stats_.malloced - accumulated_stats_.freed;
    114 }
    115 
    116 size_t AsanThreadRegistry::GetHeapSize() {
    117   ScopedLock lock(&mu_);
    118   UpdateAccumulatedStatsUnlocked();
    119   return accumulated_stats_.mmaped;
    120 }
    121 
    122 size_t AsanThreadRegistry::GetFreeBytes() {
    123   ScopedLock lock(&mu_);
    124   UpdateAccumulatedStatsUnlocked();
    125   return accumulated_stats_.mmaped
    126          - accumulated_stats_.malloced
    127          - accumulated_stats_.malloced_redzones
    128          + accumulated_stats_.really_freed
    129          + accumulated_stats_.really_freed_redzones;
    130 }
    131 
    132 AsanThreadSummary *AsanThreadRegistry::FindByTid(int tid) {
    133   CHECK(tid >= 0);
    134   CHECK(tid < n_threads_);
    135   CHECK(thread_summaries_[tid]);
    136   return thread_summaries_[tid];
    137 }
    138 
    139 AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uintptr_t addr) {
    140   ScopedLock lock(&mu_);
    141   // Main thread (tid = 0) stack limits are pretty much guessed; for the other
    142   // threads we ask libpthread, so their limits must be correct.
    143   // Scanning the thread list backwards makes this function more reliable.
    144   for (int tid = n_threads_ - 1; tid >= 0; tid--) {
    145     AsanThread *t = thread_summaries_[tid]->thread();
    146     if (!t || !(t->fake_stack().StackSize())) continue;
    147     if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
    148       return t;
    149     }
    150   }
    151   return 0;
    152 }
    153 
    154 void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
    155   for (int tid = 0; tid < n_threads_; tid++) {
    156     AsanThread *t = thread_summaries_[tid]->thread();
    157     if (t != NULL) {
    158       FlushToAccumulatedStatsUnlocked(&t->stats());
    159     }
    160   }
    161 }
    162 
    163 void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
    164   // AsanStats consists of variables of type size_t only.
    165   size_t *dst = (size_t*)&accumulated_stats_;
    166   size_t *src = (size_t*)stats;
    167   size_t num_fields = sizeof(AsanStats) / sizeof(size_t);
    168   for (size_t i = 0; i < num_fields; i++) {
    169     dst[i] += src[i];
    170     src[i] = 0;
    171   }
    172 }
    173 
    174 }  // namespace __asan
    175