2012-10-29 Wei Mi <wmi@google.com>
[official-gcc.git] / libasan / asan_globals.cc
blobb195a9091b34ba6311d38a51a957b75e7630c914
1 //===-- asan_globals.cc ---------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of AddressSanitizer, an address sanity checker.
9 //
10 // Handle globals.
11 //===----------------------------------------------------------------------===//
12 #include "asan_interceptors.h"
13 #include "asan_internal.h"
14 #include "asan_lock.h"
15 #include "asan_mapping.h"
16 #include "asan_report.h"
17 #include "asan_stack.h"
18 #include "asan_stats.h"
19 #include "asan_thread.h"
20 #include "sanitizer/asan_interface.h"
22 namespace __asan {
24 typedef __asan_global Global;
26 struct ListOfGlobals {
27 const Global *g;
28 ListOfGlobals *next;
31 static AsanLock mu_for_globals(LINKER_INITIALIZED);
32 static LowLevelAllocator allocator_for_globals;
33 static ListOfGlobals *list_of_all_globals;
34 static ListOfGlobals *list_of_dynamic_init_globals;
36 void PoisonRedZones(const Global &g) {
37 uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
38 CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4);
39 // full right redzone
40 uptr g_aligned_size = kGlobalAndStackRedzone *
41 ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
42 PoisonShadow(g.beg + g_aligned_size,
43 kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic);
44 if ((g.size % kGlobalAndStackRedzone) != 0) {
45 // partial right redzone
46 u64 g_aligned_down_size = kGlobalAndStackRedzone *
47 (g.size / kGlobalAndStackRedzone);
48 CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone);
49 PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size,
50 g.size % kGlobalAndStackRedzone,
51 kGlobalAndStackRedzone,
52 kAsanGlobalRedzoneMagic);
56 static uptr GetAlignedSize(uptr size) {
57 return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone)
58 * kGlobalAndStackRedzone;
61 bool DescribeAddressIfGlobal(uptr addr) {
62 if (!flags()->report_globals) return false;
63 ScopedLock lock(&mu_for_globals);
64 bool res = false;
65 for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
66 const Global &g = *l->g;
67 if (flags()->report_globals >= 2)
68 Report("Search Global: beg=%p size=%zu name=%s\n",
69 (void*)g.beg, g.size, (char*)g.name);
70 res |= DescribeAddressRelativeToGlobal(addr, g);
72 return res;
75 // Register a global variable.
76 // This function may be called more than once for every global
77 // so we store the globals in a map.
78 static void RegisterGlobal(const Global *g) {
79 CHECK(asan_inited);
80 if (flags()->report_globals >= 2)
81 Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n",
82 (void*)g->beg, g->size, g->size_with_redzone, g->name,
83 g->has_dynamic_init);
84 CHECK(flags()->report_globals);
85 CHECK(AddrIsInMem(g->beg));
86 CHECK(AddrIsAlignedByGranularity(g->beg));
87 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
88 PoisonRedZones(*g);
89 ListOfGlobals *l =
90 (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
91 l->g = g;
92 l->next = list_of_all_globals;
93 list_of_all_globals = l;
94 if (g->has_dynamic_init) {
95 l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
96 l->g = g;
97 l->next = list_of_dynamic_init_globals;
98 list_of_dynamic_init_globals = l;
102 static void UnregisterGlobal(const Global *g) {
103 CHECK(asan_inited);
104 CHECK(flags()->report_globals);
105 CHECK(AddrIsInMem(g->beg));
106 CHECK(AddrIsAlignedByGranularity(g->beg));
107 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
108 PoisonShadow(g->beg, g->size_with_redzone, 0);
109 // We unpoison the shadow memory for the global but we do not remove it from
110 // the list because that would require O(n^2) time with the current list
111 // implementation. It might not be worth doing anyway.
114 // Poison all shadow memory for a single global.
115 static void PoisonGlobalAndRedzones(const Global *g) {
116 CHECK(asan_inited);
117 CHECK(flags()->check_initialization_order);
118 CHECK(AddrIsInMem(g->beg));
119 CHECK(AddrIsAlignedByGranularity(g->beg));
120 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
121 if (flags()->report_globals >= 3)
122 Printf("DynInitPoison : %s\n", g->name);
123 PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
126 static void UnpoisonGlobal(const Global *g) {
127 CHECK(asan_inited);
128 CHECK(flags()->check_initialization_order);
129 CHECK(AddrIsInMem(g->beg));
130 CHECK(AddrIsAlignedByGranularity(g->beg));
131 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
132 if (flags()->report_globals >= 3)
133 Printf("DynInitUnpoison: %s\n", g->name);
134 PoisonShadow(g->beg, g->size_with_redzone, 0);
135 PoisonRedZones(*g);
138 } // namespace __asan
140 // ---------------------- Interface ---------------- {{{1
141 using namespace __asan; // NOLINT
143 // Register one global with a default redzone.
144 void __asan_register_global(uptr addr, uptr size,
145 const char *name) {
146 if (!flags()->report_globals) return;
147 ScopedLock lock(&mu_for_globals);
148 Global *g = (Global *)allocator_for_globals.Allocate(sizeof(Global));
149 g->beg = addr;
150 g->size = size;
151 g->size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone;
152 g->name = name;
153 RegisterGlobal(g);
156 // Register an array of globals.
157 void __asan_register_globals(__asan_global *globals, uptr n) {
158 if (!flags()->report_globals) return;
159 ScopedLock lock(&mu_for_globals);
160 for (uptr i = 0; i < n; i++) {
161 RegisterGlobal(&globals[i]);
165 // Unregister an array of globals.
166 // We must do this when a shared objects gets dlclosed.
167 void __asan_unregister_globals(__asan_global *globals, uptr n) {
168 if (!flags()->report_globals) return;
169 ScopedLock lock(&mu_for_globals);
170 for (uptr i = 0; i < n; i++) {
171 UnregisterGlobal(&globals[i]);
175 // This method runs immediately prior to dynamic initialization in each TU,
176 // when all dynamically initialized globals are unpoisoned. This method
177 // poisons all global variables not defined in this TU, so that a dynamic
178 // initializer can only touch global variables in the same TU.
179 void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) {
180 if (!flags()->check_initialization_order) return;
181 CHECK(list_of_dynamic_init_globals);
182 ScopedLock lock(&mu_for_globals);
183 bool from_current_tu = false;
184 // The list looks like:
185 // a => ... => b => last_addr => ... => first_addr => c => ...
186 // The globals of the current TU reside between last_addr and first_addr.
187 for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
188 if (l->g->beg == last_addr)
189 from_current_tu = true;
190 if (!from_current_tu)
191 PoisonGlobalAndRedzones(l->g);
192 if (l->g->beg == first_addr)
193 from_current_tu = false;
195 CHECK(!from_current_tu);
198 // This method runs immediately after dynamic initialization in each TU, when
199 // all dynamically initialized globals except for those defined in the current
200 // TU are poisoned. It simply unpoisons all dynamically initialized globals.
201 void __asan_after_dynamic_init() {
202 if (!flags()->check_initialization_order) return;
203 ScopedLock lock(&mu_for_globals);
204 for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
205 UnpoisonGlobal(l->g);