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