asan_globals.cc revision 1e172b4bdec57329bf904f063a29f99cddf2d85f
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#include <map> 25 26namespace __asan { 27 28typedef __asan_global Global; 29 30static AsanLock mu_for_globals(LINKER_INITIALIZED); 31typedef std::map<uintptr_t, Global> MapOfGlobals; 32static MapOfGlobals *g_all_globals = NULL; 33 34void PoisonRedZones(const Global &g) { 35 uintptr_t shadow = MemToShadow(g.beg); 36 size_t ShadowRZSize = kGlobalAndStackRedzone >> SHADOW_SCALE; 37 CHECK(ShadowRZSize == 1 || ShadowRZSize == 2 || ShadowRZSize == 4); 38 // full right redzone 39 uintptr_t right_rz2_offset = ShadowRZSize * 40 ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone); 41 real_memset((uint8_t*)shadow + right_rz2_offset, 42 kAsanGlobalRedzoneMagic, ShadowRZSize); 43 if ((g.size % kGlobalAndStackRedzone) != 0) { 44 // partial right redzone 45 uint64_t right_rz1_offset = 46 ShadowRZSize * (g.size / kGlobalAndStackRedzone); 47 CHECK(right_rz1_offset == right_rz2_offset - ShadowRZSize); 48 PoisonShadowPartialRightRedzone((uint8_t*)(shadow + right_rz1_offset), 49 g.size % kGlobalAndStackRedzone, 50 kGlobalAndStackRedzone, 51 SHADOW_GRANULARITY, 52 kAsanGlobalRedzoneMagic); 53 } 54} 55 56static size_t GetAlignedSize(size_t size) { 57 return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone) 58 * kGlobalAndStackRedzone; 59} 60 61 // Check if the global is a zero-terminated ASCII string. If so, print it. 62void PrintIfASCII(const Global &g) { 63 for (size_t p = g.beg; p < g.beg + g.size - 1; p++) { 64 if (!isascii(*(char*)p)) return; 65 } 66 if (*(char*)(g.beg + g.size - 1) != 0) return; 67 Printf(" '%s' is ascii string '%s'\n", g.name, g.beg); 68} 69 70bool DescribeAddrIfMyRedZone(const Global &g, uintptr_t addr) { 71 if (addr < g.beg - kGlobalAndStackRedzone) return false; 72 if (addr >= g.beg + g.size_with_redzone) return false; 73 Printf("%p is located ", addr); 74 if (addr < g.beg) { 75 Printf("%d bytes to the left", g.beg - addr); 76 } else if (addr >= g.beg + g.size) { 77 Printf("%d bytes to the right", addr - (g.beg + g.size)); 78 } else { 79 Printf("%d bytes inside", addr - g.beg); // Can it happen? 80 } 81 Printf(" of global variable '%s' (0x%lx) of size %ld\n", 82 g.name, g.beg, g.size); 83 PrintIfASCII(g); 84 return true; 85} 86 87 88bool DescribeAddrIfGlobal(uintptr_t addr) { 89 if (!FLAG_report_globals) return false; 90 ScopedLock lock(&mu_for_globals); 91 if (!g_all_globals) return false; 92 bool res = false; 93 // Just iterate. May want to use binary search instead. 94 for (MapOfGlobals::iterator i = g_all_globals->begin(), 95 end = g_all_globals->end(); i != end; ++i) { 96 Global &g = i->second; 97 CHECK(i->first == g.beg); 98 if (FLAG_report_globals >= 2) 99 Printf("Search Global: beg=%p size=%ld name=%s\n", 100 g.beg, g.size, g.name); 101 res |= DescribeAddrIfMyRedZone(g, addr); 102 } 103 return res; 104} 105 106// Register a global variable. 107// This function may be called more than once for every global 108// so we store the globals in a map. 109static void RegisterGlobal(const Global *g) { 110 CHECK(asan_inited); 111 if (!FLAG_report_globals) return; 112 ScopedLock lock(&mu_for_globals); 113 if (!g_all_globals) 114 g_all_globals = new MapOfGlobals; 115 CHECK(AddrIsInMem(g->beg)); 116 if (FLAG_report_globals >= 2) 117 Printf("Added Global: beg=%p size=%ld name=%s\n", 118 g->beg, g->size, g->name); 119 PoisonRedZones(*g); 120 (*g_all_globals)[g->beg] = *g; 121} 122 123} // namespace __asan 124 125// ---------------------- Interface ---------------- {{{1 126using namespace __asan; // NOLINT 127 128// Register one global with a default redzone. 129void __asan_register_global(uintptr_t addr, size_t size, 130 const char *name) { 131 Global g; 132 g.beg = addr; 133 g.size = size; 134 g.size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone; 135 g.name = name; 136 RegisterGlobal(&g); 137} 138 139// Register an array of globals. 140void __asan_register_globals(__asan_global *globals, size_t n) { 141 for (size_t i = 0; i < n; i++) { 142 RegisterGlobal(&globals[i]); 143 } 144} 145