asan_globals.cc revision 53177247698bfba075f2d5b255a447fc3ced6976
1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//===-- asan_globals.cc ---------------------------------------------------===//
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//
3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//                     The LLVM Compiler Infrastructure
4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// This file is distributed under the University of Illinois Open Source
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// License. See LICENSE.TXT for details.
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//===----------------------------------------------------------------------===//
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// This file is a part of AddressSanitizer, an address sanity checker.
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Handle globals.
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks//===----------------------------------------------------------------------===//
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "asan_interceptors.h"
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "asan_internal.h"
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "asan_mapping.h"
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "asan_poisoning.h"
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "asan_report.h"
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "asan_stack.h"
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "asan_stats.h"
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "asan_thread.h"
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "sanitizer_common/sanitizer_common.h"
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "sanitizer_common/sanitizer_mutex.h"
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "sanitizer_common/sanitizer_placement_new.h"
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksnamespace __asan {
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickstypedef __asan_global Global;
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstruct ListOfGlobals {
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  const Global *g;
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  ListOfGlobals *next;
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks};
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic BlockingMutex mu_for_globals(LINKER_INITIALIZED);
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic LowLevelAllocator allocator_for_globals;
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic ListOfGlobals *list_of_all_globals;
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic const int kDynamicInitGlobalsInitialCapacity = 512;
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstruct DynInitGlobal {
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  Global g;
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  bool initialized;
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks};
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickstypedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Lazy-initialized and never deleted.
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic VectorOfGlobals *dynamic_init_globals;
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin HendricksALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  FastPoisonShadow(g->beg, g->size_with_redzone, value);
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin HendricksALWAYS_INLINE void PoisonRedZones(const Global &g) {
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                   kAsanGlobalRedzoneMagic);
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (g.size != aligned_size) {
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    FastPoisonShadowPartialRightRedzone(
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        g.size % SHADOW_GRANULARITY,
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        SHADOW_GRANULARITY,
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        kAsanGlobalRedzoneMagic);
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  }
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic void ReportGlobal(const Global &g, const char *prefix) {
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         g.module_name, g.has_dynamic_init);
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksbool DescribeAddressIfGlobal(uptr addr, uptr size) {
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (!flags()->report_globals) return false;
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  BlockingMutexLock lock(&mu_for_globals);
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  bool res = false;
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    const Global &g = *l->g;
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    if (flags()->report_globals >= 2)
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      ReportGlobal(g, "Search");
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    res |= DescribeAddressRelativeToGlobal(addr, size, g);
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  }
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  return res;
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Register a global variable.
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// This function may be called more than once for every global
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// so we store the globals in a map.
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic void RegisterGlobal(const Global *g) {
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(asan_inited);
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (flags()->report_globals >= 2)
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    ReportGlobal(*g, "Added");
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(flags()->report_globals);
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(AddrIsInMem(g->beg));
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(AddrIsAlignedByGranularity(g->beg));
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (flags()->poison_heap)
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    PoisonRedZones(*g);
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  l->g = g;
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  l->next = list_of_all_globals;
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  list_of_all_globals = l;
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (g->has_dynamic_init) {
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    if (dynamic_init_globals == 0) {
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      dynamic_init_globals = new(allocator_for_globals)
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks          VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    DynInitGlobal dyn_global = { *g, false };
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    dynamic_init_globals->push_back(dyn_global);
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  }
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic void UnregisterGlobal(const Global *g) {
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(asan_inited);
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(flags()->report_globals);
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(AddrIsInMem(g->beg));
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(AddrIsAlignedByGranularity(g->beg));
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
117  if (flags()->poison_heap)
118    PoisonShadowForGlobal(g, 0);
119  // We unpoison the shadow memory for the global but we do not remove it from
120  // the list because that would require O(n^2) time with the current list
121  // implementation. It might not be worth doing anyway.
122}
123
124void StopInitOrderChecking() {
125  BlockingMutexLock lock(&mu_for_globals);
126  if (!flags()->check_initialization_order || !dynamic_init_globals)
127    return;
128  flags()->check_initialization_order = false;
129  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
130    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
131    const Global *g = &dyn_g.g;
132    // Unpoison the whole global.
133    PoisonShadowForGlobal(g, 0);
134    // Poison redzones back.
135    PoisonRedZones(*g);
136  }
137}
138
139}  // namespace __asan
140
141// ---------------------- Interface ---------------- {{{1
142using namespace __asan;  // NOLINT
143
144// Register an array of globals.
145void __asan_register_globals(__asan_global *globals, uptr n) {
146  if (!flags()->report_globals) return;
147  BlockingMutexLock lock(&mu_for_globals);
148  for (uptr i = 0; i < n; i++) {
149    RegisterGlobal(&globals[i]);
150  }
151}
152
153// Unregister an array of globals.
154// We must do this when a shared objects gets dlclosed.
155void __asan_unregister_globals(__asan_global *globals, uptr n) {
156  if (!flags()->report_globals) return;
157  BlockingMutexLock lock(&mu_for_globals);
158  for (uptr i = 0; i < n; i++) {
159    UnregisterGlobal(&globals[i]);
160  }
161}
162
163// This method runs immediately prior to dynamic initialization in each TU,
164// when all dynamically initialized globals are unpoisoned.  This method
165// poisons all global variables not defined in this TU, so that a dynamic
166// initializer can only touch global variables in the same TU.
167void __asan_before_dynamic_init(const char *module_name) {
168  if (!flags()->check_initialization_order ||
169      !flags()->poison_heap)
170    return;
171  bool strict_init_order = flags()->strict_init_order;
172  CHECK(dynamic_init_globals);
173  CHECK(module_name);
174  CHECK(asan_inited);
175  BlockingMutexLock lock(&mu_for_globals);
176  if (flags()->report_globals >= 3)
177    Printf("DynInitPoison module: %s\n", module_name);
178  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
179    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
180    const Global *g = &dyn_g.g;
181    if (dyn_g.initialized)
182      continue;
183    if (g->module_name != module_name)
184      PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
185    else if (!strict_init_order)
186      dyn_g.initialized = true;
187  }
188}
189
190// This method runs immediately after dynamic initialization in each TU, when
191// all dynamically initialized globals except for those defined in the current
192// TU are poisoned.  It simply unpoisons all dynamically initialized globals.
193void __asan_after_dynamic_init() {
194  if (!flags()->check_initialization_order ||
195      !flags()->poison_heap)
196    return;
197  CHECK(asan_inited);
198  BlockingMutexLock lock(&mu_for_globals);
199  // FIXME: Optionally report that we're unpoisoning globals from a module.
200  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
201    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
202    const Global *g = &dyn_g.g;
203    if (!dyn_g.initialized) {
204      // Unpoison the whole global.
205      PoisonShadowForGlobal(g, 0);
206      // Poison redzones back.
207      PoisonRedZones(*g);
208    }
209  }
210}
211