asan_globals.cc revision e4bfca2b154a6ab4eda921aff454035f33f3551a
1//===-- asan_globals.cc ---------------------------------------------------===//
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_report.h"
20#include "asan_stack.h"
21#include "asan_stats.h"
22#include "asan_thread.h"
23
24namespace __asan {
25
26typedef __asan_global Global;
27
28struct ListOfGlobals {
29  const Global *g;
30  ListOfGlobals *next;
31};
32
33static AsanLock mu_for_globals(LINKER_INITIALIZED);
34static ListOfGlobals *list_of_globals;
35static LowLevelAllocator allocator_for_globals(LINKER_INITIALIZED);
36
37void PoisonRedZones(const Global &g)  {
38  uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
39  CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4);
40  // full right redzone
41  uptr g_aligned_size = kGlobalAndStackRedzone *
42      ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
43  PoisonShadow(g.beg + g_aligned_size,
44               kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic);
45  if ((g.size % kGlobalAndStackRedzone) != 0) {
46    // partial right redzone
47    u64 g_aligned_down_size = kGlobalAndStackRedzone *
48        (g.size / kGlobalAndStackRedzone);
49    CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone);
50    PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size,
51                                    g.size % kGlobalAndStackRedzone,
52                                    kGlobalAndStackRedzone,
53                                    kAsanGlobalRedzoneMagic);
54  }
55}
56
57static uptr GetAlignedSize(uptr size) {
58  return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone)
59      * kGlobalAndStackRedzone;
60}
61
62bool DescribeAddressIfGlobal(uptr addr) {
63  if (!flags()->report_globals) return false;
64  ScopedLock lock(&mu_for_globals);
65  bool res = false;
66  for (ListOfGlobals *l = list_of_globals; l; l = l->next) {
67    const Global &g = *l->g;
68    if (flags()->report_globals >= 2)
69      Report("Search Global: beg=%p size=%zu name=%s\n",
70             (void*)g.beg, g.size, (char*)g.name);
71    res |= DescribeAddressRelativeToGlobal(addr, g);
72  }
73  return res;
74}
75
76// Register a global variable.
77// This function may be called more than once for every global
78// so we store the globals in a map.
79static void RegisterGlobal(const Global *g) {
80  CHECK(asan_inited);
81  CHECK(flags()->report_globals);
82  CHECK(AddrIsInMem(g->beg));
83  CHECK(AddrIsAlignedByGranularity(g->beg));
84  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
85  PoisonRedZones(*g);
86  ListOfGlobals *l =
87      (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
88  l->g = g;
89  l->next = list_of_globals;
90  list_of_globals = l;
91  if (flags()->report_globals >= 2)
92    Report("Added Global: beg=%p size=%zu name=%s\n",
93           (void*)g->beg, g->size, g->name);
94}
95
96static void UnregisterGlobal(const Global *g) {
97  CHECK(asan_inited);
98  CHECK(flags()->report_globals);
99  CHECK(AddrIsInMem(g->beg));
100  CHECK(AddrIsAlignedByGranularity(g->beg));
101  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
102  PoisonShadow(g->beg, g->size_with_redzone, 0);
103  // We unpoison the shadow memory for the global but we do not remove it from
104  // the list because that would require O(n^2) time with the current list
105  // implementation. It might not be worth doing anyway.
106}
107
108}  // namespace __asan
109
110// ---------------------- Interface ---------------- {{{1
111using namespace __asan;  // NOLINT
112
113// Register one global with a default redzone.
114void __asan_register_global(uptr addr, uptr size,
115                            const char *name) {
116  if (!flags()->report_globals) return;
117  ScopedLock lock(&mu_for_globals);
118  Global *g = (Global *)allocator_for_globals.Allocate(sizeof(Global));
119  g->beg = addr;
120  g->size = size;
121  g->size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone;
122  g->name = name;
123  RegisterGlobal(g);
124}
125
126// Register an array of globals.
127void __asan_register_globals(__asan_global *globals, uptr n) {
128  if (!flags()->report_globals) return;
129  ScopedLock lock(&mu_for_globals);
130  for (uptr i = 0; i < n; i++) {
131    RegisterGlobal(&globals[i]);
132  }
133}
134
135// Unregister an array of globals.
136// We must do it when a shared objects gets dlclosed.
137void __asan_unregister_globals(__asan_global *globals, uptr n) {
138  if (!flags()->report_globals) return;
139  ScopedLock lock(&mu_for_globals);
140  for (uptr i = 0; i < n; i++) {
141    UnregisterGlobal(&globals[i]);
142  }
143}
144