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