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