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 25namespace __asan { 26 27typedef __asan_global Global; 28 29struct ListOfGlobals { 30 const Global *g; 31 ListOfGlobals *next; 32}; 33 34static AsanLock mu_for_globals(LINKER_INITIALIZED); 35static ListOfGlobals *list_of_globals; 36static LowLevelAllocator allocator_for_globals(LINKER_INITIALIZED); 37 38void 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 58static 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. 64void 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 72bool 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 90bool 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. 107static 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 124static 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 139using namespace __asan; // NOLINT 140 141// Register one global with a default redzone. 142void __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. 155void __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. 165void __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