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