asan_globals.cc revision 218a9b70d7338cf5b727b7dad6b080ad7869c6c2
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 size_t shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE; 36 CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4); 37 // full right redzone 38 size_t g_aligned_size = kGlobalAndStackRedzone * 39 ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone); 40 PoisonShadow(g.beg + g_aligned_size, 41 kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic); 42 if ((g.size % kGlobalAndStackRedzone) != 0) { 43 // partial right redzone 44 uint64_t g_aligned_down_size = kGlobalAndStackRedzone * 45 (g.size / kGlobalAndStackRedzone); 46 CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone); 47 PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size, 48 g.size % kGlobalAndStackRedzone, 49 kGlobalAndStackRedzone, 50 kAsanGlobalRedzoneMagic); 51 } 52} 53 54static size_t GetAlignedSize(size_t size) { 55 return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone) 56 * kGlobalAndStackRedzone; 57} 58 59 // Check if the global is a zero-terminated ASCII string. If so, print it. 60void PrintIfASCII(const Global &g) { 61 for (size_t p = g.beg; p < g.beg + g.size - 1; p++) { 62 if (!isascii(*(char*)p)) return; 63 } 64 if (*(char*)(g.beg + g.size - 1) != 0) return; 65 Printf(" '%s' is ascii string '%s'\n", g.name, g.beg); 66} 67 68bool DescribeAddrIfMyRedZone(const Global &g, uintptr_t addr) { 69 if (addr < g.beg - kGlobalAndStackRedzone) return false; 70 if (addr >= g.beg + g.size_with_redzone) return false; 71 Printf("%p is located ", addr); 72 if (addr < g.beg) { 73 Printf("%d bytes to the left", g.beg - addr); 74 } else if (addr >= g.beg + g.size) { 75 Printf("%d bytes to the right", addr - (g.beg + g.size)); 76 } else { 77 Printf("%d bytes inside", addr - g.beg); // Can it happen? 78 } 79 Printf(" of global variable '%s' (0x%lx) of size %ld\n", 80 g.name, g.beg, g.size); 81 PrintIfASCII(g); 82 return true; 83} 84 85 86bool DescribeAddrIfGlobal(uintptr_t addr) { 87 if (!FLAG_report_globals) return false; 88 ScopedLock lock(&mu_for_globals); 89 if (!g_all_globals) return false; 90 bool res = false; 91 // Just iterate. May want to use binary search instead. 92 for (MapOfGlobals::iterator i = g_all_globals->begin(), 93 end = g_all_globals->end(); i != end; ++i) { 94 Global &g = i->second; 95 CHECK(i->first == g.beg); 96 if (FLAG_report_globals >= 2) 97 Printf("Search Global: beg=%p size=%ld 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 if (!FLAG_report_globals) return; 110 ScopedLock lock(&mu_for_globals); 111 if (!g_all_globals) 112 g_all_globals = new MapOfGlobals; 113 CHECK(AddrIsInMem(g->beg)); 114 if (FLAG_report_globals >= 2) 115 Printf("Added Global: beg=%p size=%ld name=%s\n", 116 g->beg, g->size, g->name); 117 CHECK(AddrIsAlignedByGranularity(g->beg)); 118 PoisonRedZones(*g); 119 (*g_all_globals)[g->beg] = *g; 120} 121 122} // namespace __asan 123 124// ---------------------- Interface ---------------- {{{1 125using namespace __asan; // NOLINT 126 127// Register one global with a default redzone. 128void __asan_register_global(uintptr_t addr, size_t size, 129 const char *name) { 130 Global g; 131 g.beg = addr; 132 g.size = size; 133 g.size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone; 134 g.name = name; 135 RegisterGlobal(&g); 136} 137 138// Register an array of globals. 139void __asan_register_globals(__asan_global *globals, size_t n) { 140 for (size_t i = 0; i < n; i++) { 141 RegisterGlobal(&globals[i]); 142 } 143} 144