Home | History | Annotate | Download | only in asan
      1 //===-- asan_globals.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 // Handle globals.
     13 //===----------------------------------------------------------------------===//
     14 #include "asan_interceptors.h"
     15 #include "asan_internal.h"
     16 #include "asan_mapping.h"
     17 #include "asan_report.h"
     18 #include "asan_stack.h"
     19 #include "asan_stats.h"
     20 #include "asan_thread.h"
     21 #include "sanitizer_common/sanitizer_mutex.h"
     22 
     23 namespace __asan {
     24 
     25 typedef __asan_global Global;
     26 
     27 struct ListOfGlobals {
     28   const Global *g;
     29   ListOfGlobals *next;
     30 };
     31 
     32 static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
     33 static LowLevelAllocator allocator_for_globals;
     34 static ListOfGlobals *list_of_all_globals;
     35 static ListOfGlobals *list_of_dynamic_init_globals;
     36 
     37 void PoisonRedZones(const Global &g)  {
     38   uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
     39   PoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
     40                kAsanGlobalRedzoneMagic);
     41   if (g.size != aligned_size) {
     42     // partial right redzone
     43     PoisonShadowPartialRightRedzone(
     44         g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
     45         g.size % SHADOW_GRANULARITY,
     46         SHADOW_GRANULARITY,
     47         kAsanGlobalRedzoneMagic);
     48   }
     49 }
     50 
     51 bool DescribeAddressIfGlobal(uptr addr, uptr size) {
     52   if (!flags()->report_globals) return false;
     53   BlockingMutexLock lock(&mu_for_globals);
     54   bool res = false;
     55   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
     56     const Global &g = *l->g;
     57     if (flags()->report_globals >= 2)
     58       Report("Search Global: beg=%p size=%zu name=%s\n",
     59              (void*)g.beg, g.size, (char*)g.name);
     60     res |= DescribeAddressRelativeToGlobal(addr, size, g);
     61   }
     62   return res;
     63 }
     64 
     65 // Register a global variable.
     66 // This function may be called more than once for every global
     67 // so we store the globals in a map.
     68 static void RegisterGlobal(const Global *g) {
     69   CHECK(asan_inited);
     70   if (flags()->report_globals >= 2)
     71     Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n",
     72            (void*)g->beg, g->size, g->size_with_redzone, g->name,
     73            g->has_dynamic_init);
     74   CHECK(flags()->report_globals);
     75   CHECK(AddrIsInMem(g->beg));
     76   CHECK(AddrIsAlignedByGranularity(g->beg));
     77   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
     78   PoisonRedZones(*g);
     79   ListOfGlobals *l =
     80       (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
     81   l->g = g;
     82   l->next = list_of_all_globals;
     83   list_of_all_globals = l;
     84   if (g->has_dynamic_init) {
     85     l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
     86     l->g = g;
     87     l->next = list_of_dynamic_init_globals;
     88     list_of_dynamic_init_globals = l;
     89   }
     90 }
     91 
     92 static void UnregisterGlobal(const Global *g) {
     93   CHECK(asan_inited);
     94   CHECK(flags()->report_globals);
     95   CHECK(AddrIsInMem(g->beg));
     96   CHECK(AddrIsAlignedByGranularity(g->beg));
     97   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
     98   PoisonShadow(g->beg, g->size_with_redzone, 0);
     99   // We unpoison the shadow memory for the global but we do not remove it from
    100   // the list because that would require O(n^2) time with the current list
    101   // implementation. It might not be worth doing anyway.
    102 }
    103 
    104 // Poison all shadow memory for a single global.
    105 static void PoisonGlobalAndRedzones(const Global *g) {
    106   CHECK(asan_inited);
    107   CHECK(flags()->check_initialization_order);
    108   CHECK(AddrIsInMem(g->beg));
    109   CHECK(AddrIsAlignedByGranularity(g->beg));
    110   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
    111   if (flags()->report_globals >= 3)
    112     Printf("DynInitPoison  : %s\n", g->name);
    113   PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
    114 }
    115 
    116 static void UnpoisonGlobal(const Global *g) {
    117   CHECK(asan_inited);
    118   CHECK(flags()->check_initialization_order);
    119   CHECK(AddrIsInMem(g->beg));
    120   CHECK(AddrIsAlignedByGranularity(g->beg));
    121   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
    122   if (flags()->report_globals >= 3)
    123     Printf("DynInitUnpoison: %s\n", g->name);
    124   PoisonShadow(g->beg, g->size_with_redzone, 0);
    125   PoisonRedZones(*g);
    126 }
    127 
    128 }  // namespace __asan
    129 
    130 // ---------------------- Interface ---------------- {{{1
    131 using namespace __asan;  // NOLINT
    132 
    133 // Register an array of globals.
    134 void __asan_register_globals(__asan_global *globals, uptr n) {
    135   if (!flags()->report_globals) return;
    136   BlockingMutexLock lock(&mu_for_globals);
    137   for (uptr i = 0; i < n; i++) {
    138     RegisterGlobal(&globals[i]);
    139   }
    140 }
    141 
    142 // Unregister an array of globals.
    143 // We must do this when a shared objects gets dlclosed.
    144 void __asan_unregister_globals(__asan_global *globals, uptr n) {
    145   if (!flags()->report_globals) return;
    146   BlockingMutexLock lock(&mu_for_globals);
    147   for (uptr i = 0; i < n; i++) {
    148     UnregisterGlobal(&globals[i]);
    149   }
    150 }
    151 
    152 // This method runs immediately prior to dynamic initialization in each TU,
    153 // when all dynamically initialized globals are unpoisoned.  This method
    154 // poisons all global variables not defined in this TU, so that a dynamic
    155 // initializer can only touch global variables in the same TU.
    156 void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) {
    157   if (!flags()->check_initialization_order) return;
    158   CHECK(list_of_dynamic_init_globals);
    159   BlockingMutexLock lock(&mu_for_globals);
    160   bool from_current_tu = false;
    161   // The list looks like:
    162   // a => ... => b => last_addr => ... => first_addr => c => ...
    163   // The globals of the current TU reside between last_addr and first_addr.
    164   for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
    165     if (l->g->beg == last_addr)
    166       from_current_tu = true;
    167     if (!from_current_tu)
    168       PoisonGlobalAndRedzones(l->g);
    169     if (l->g->beg == first_addr)
    170       from_current_tu = false;
    171   }
    172   CHECK(!from_current_tu);
    173 }
    174 
    175 // This method runs immediately after dynamic initialization in each TU, when
    176 // all dynamically initialized globals except for those defined in the current
    177 // TU are poisoned.  It simply unpoisons all dynamically initialized globals.
    178 void __asan_after_dynamic_init() {
    179   if (!flags()->check_initialization_order) return;
    180   BlockingMutexLock lock(&mu_for_globals);
    181   for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
    182     UnpoisonGlobal(l->g);
    183 }
    184