asan_globals.cc revision 39cbb56fb3ba2af53e537107862c51f1dd252150
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 23namespace __asan { 24 25typedef __asan_global Global; 26 27struct ListOfGlobals { 28 const Global *g; 29 ListOfGlobals *next; 30}; 31 32static BlockingMutex mu_for_globals(LINKER_INITIALIZED); 33static LowLevelAllocator allocator_for_globals; 34static ListOfGlobals *list_of_all_globals; 35static ListOfGlobals *list_of_dynamic_init_globals; 36 37static 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 51bool 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. 68static 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 92static 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. 105static 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 116static 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 131using namespace __asan; // NOLINT 132 133// Register an array of globals. 134void __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. 144void __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. 156void __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. 178void __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