Home | History | Annotate | Download | only in asan
      1 //===-- asan_globals.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 // Handle globals.
     13 //===----------------------------------------------------------------------===//
     14 #include "asan_interceptors.h"
     15 #include "asan_interface.h"
     16 #include "asan_internal.h"
     17 #include "asan_lock.h"
     18 #include "asan_mapping.h"
     19 #include "asan_stack.h"
     20 #include "asan_stats.h"
     21 #include "asan_thread.h"
     22 
     23 #include <ctype.h>
     24 
     25 namespace __asan {
     26 
     27 typedef __asan_global Global;
     28 
     29 struct ListOfGlobals {
     30   const Global *g;
     31   ListOfGlobals *next;
     32 };
     33 
     34 static AsanLock mu_for_globals(LINKER_INITIALIZED);
     35 static ListOfGlobals *list_of_globals;
     36 static LowLevelAllocator allocator_for_globals(LINKER_INITIALIZED);
     37 
     38 void PoisonRedZones(const Global &g)  {
     39   size_t shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
     40   CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4);
     41   // full right redzone
     42   size_t g_aligned_size = kGlobalAndStackRedzone *
     43       ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
     44   PoisonShadow(g.beg + g_aligned_size,
     45                kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic);
     46   if ((g.size % kGlobalAndStackRedzone) != 0) {
     47     // partial right redzone
     48     uint64_t g_aligned_down_size = kGlobalAndStackRedzone *
     49         (g.size / kGlobalAndStackRedzone);
     50     CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone);
     51     PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size,
     52                                     g.size % kGlobalAndStackRedzone,
     53                                     kGlobalAndStackRedzone,
     54                                     kAsanGlobalRedzoneMagic);
     55   }
     56 }
     57 
     58 static size_t GetAlignedSize(size_t size) {
     59   return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone)
     60       * kGlobalAndStackRedzone;
     61 }
     62 
     63   // Check if the global is a zero-terminated ASCII string. If so, print it.
     64 void PrintIfASCII(const Global &g) {
     65   for (size_t p = g.beg; p < g.beg + g.size - 1; p++) {
     66     if (!isascii(*(char*)p)) return;
     67   }
     68   if (*(char*)(g.beg + g.size - 1) != 0) return;
     69   Printf("  '%s' is ascii string '%s'\n", g.name, g.beg);
     70 }
     71 
     72 bool DescribeAddrIfMyRedZone(const Global &g, uintptr_t addr) {
     73   if (addr < g.beg - kGlobalAndStackRedzone) return false;
     74   if (addr >= g.beg + g.size_with_redzone) return false;
     75   Printf("%p is located ", addr);
     76   if (addr < g.beg) {
     77     Printf("%zd bytes to the left", g.beg - addr);
     78   } else if (addr >= g.beg + g.size) {
     79     Printf("%zd bytes to the right", addr - (g.beg + g.size));
     80   } else {
     81     Printf("%zd bytes inside", addr - g.beg);  // Can it happen?
     82   }
     83   Printf(" of global variable '%s' (0x%zx) of size %zu\n",
     84          g.name, g.beg, g.size);
     85   PrintIfASCII(g);
     86   return true;
     87 }
     88 
     89 
     90 bool DescribeAddrIfGlobal(uintptr_t addr) {
     91   if (!FLAG_report_globals) return false;
     92   ScopedLock lock(&mu_for_globals);
     93   bool res = false;
     94   for (ListOfGlobals *l = list_of_globals; l; l = l->next) {
     95     const Global &g = *l->g;
     96     if (FLAG_report_globals >= 2)
     97       Printf("Search Global: beg=%p size=%zu name=%s\n",
     98              g.beg, g.size, g.name);
     99     res |= DescribeAddrIfMyRedZone(g, addr);
    100   }
    101   return res;
    102 }
    103 
    104 // Register a global variable.
    105 // This function may be called more than once for every global
    106 // so we store the globals in a map.
    107 static void RegisterGlobal(const Global *g) {
    108   CHECK(asan_inited);
    109   CHECK(FLAG_report_globals);
    110   CHECK(AddrIsInMem(g->beg));
    111   CHECK(AddrIsAlignedByGranularity(g->beg));
    112   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
    113   PoisonRedZones(*g);
    114   ListOfGlobals *l =
    115       (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
    116   l->g = g;
    117   l->next = list_of_globals;
    118   list_of_globals = l;
    119   if (FLAG_report_globals >= 2)
    120     Report("Added Global: beg=%p size=%zu name=%s\n",
    121            g->beg, g->size, g->name);
    122 }
    123 
    124 static void UnregisterGlobal(const Global *g) {
    125   CHECK(asan_inited);
    126   CHECK(FLAG_report_globals);
    127   CHECK(AddrIsInMem(g->beg));
    128   CHECK(AddrIsAlignedByGranularity(g->beg));
    129   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
    130   PoisonShadow(g->beg, g->size_with_redzone, 0);
    131   // We unpoison the shadow memory for the global but we do not remove it from
    132   // the list because that would require O(n^2) time with the current list
    133   // implementation. It might not be worth doing anyway.
    134 }
    135 
    136 }  // namespace __asan
    137 
    138 // ---------------------- Interface ---------------- {{{1
    139 using namespace __asan;  // NOLINT
    140 
    141 // Register one global with a default redzone.
    142 void __asan_register_global(uintptr_t addr, size_t size,
    143                             const char *name) {
    144   if (!FLAG_report_globals) return;
    145   ScopedLock lock(&mu_for_globals);
    146   Global *g = (Global *)allocator_for_globals.Allocate(sizeof(Global));
    147   g->beg = addr;
    148   g->size = size;
    149   g->size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone;
    150   g->name = name;
    151   RegisterGlobal(g);
    152 }
    153 
    154 // Register an array of globals.
    155 void __asan_register_globals(__asan_global *globals, size_t n) {
    156   if (!FLAG_report_globals) return;
    157   ScopedLock lock(&mu_for_globals);
    158   for (size_t i = 0; i < n; i++) {
    159     RegisterGlobal(&globals[i]);
    160   }
    161 }
    162 
    163 // Unregister an array of globals.
    164 // We must do it when a shared objects gets dlclosed.
    165 void __asan_unregister_globals(__asan_global *globals, size_t n) {
    166   if (!FLAG_report_globals) return;
    167   ScopedLock lock(&mu_for_globals);
    168   for (size_t i = 0; i < n; i++) {
    169     UnregisterGlobal(&globals[i]);
    170   }
    171 }
    172