2013-02-04 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libsanitizer / asan / asan_globals.cc
blob88aeefa8fe5e75ba24e49388a28d43d488a334aa
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_mapping.h"
15 #include "asan_report.h"
16 #include "asan_stack.h"
17 #include "asan_stats.h"
18 #include "asan_thread.h"
19 #include "sanitizer/asan_interface.h"
20 #include "sanitizer_common/sanitizer_mutex.h"
22 namespace __asan {
24 typedef __asan_global Global;
26 struct ListOfGlobals {
27 const Global *g;
28 ListOfGlobals *next;
31 static BlockingMutex 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 bool DescribeAddressIfGlobal(uptr addr) {
57 if (!flags()->report_globals) return false;
58 BlockingMutexLock lock(&mu_for_globals);
59 bool res = false;
60 for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
61 const Global &g = *l->g;
62 if (flags()->report_globals >= 2)
63 Report("Search Global: beg=%p size=%zu name=%s\n",
64 (void*)g.beg, g.size, (char*)g.name);
65 res |= DescribeAddressRelativeToGlobal(addr, g);
67 return res;
70 // Register a global variable.
71 // This function may be called more than once for every global
72 // so we store the globals in a map.
73 static void RegisterGlobal(const Global *g) {
74 CHECK(asan_inited);
75 if (flags()->report_globals >= 2)
76 Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n",
77 (void*)g->beg, g->size, g->size_with_redzone, g->name,
78 g->has_dynamic_init);
79 CHECK(flags()->report_globals);
80 CHECK(AddrIsInMem(g->beg));
81 CHECK(AddrIsAlignedByGranularity(g->beg));
82 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
83 PoisonRedZones(*g);
84 ListOfGlobals *l =
85 (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
86 l->g = g;
87 l->next = list_of_all_globals;
88 list_of_all_globals = l;
89 if (g->has_dynamic_init) {
90 l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
91 l->g = g;
92 l->next = list_of_dynamic_init_globals;
93 list_of_dynamic_init_globals = l;
97 static void UnregisterGlobal(const Global *g) {
98 CHECK(asan_inited);
99 CHECK(flags()->report_globals);
100 CHECK(AddrIsInMem(g->beg));
101 CHECK(AddrIsAlignedByGranularity(g->beg));
102 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
103 PoisonShadow(g->beg, g->size_with_redzone, 0);
104 // We unpoison the shadow memory for the global but we do not remove it from
105 // the list because that would require O(n^2) time with the current list
106 // implementation. It might not be worth doing anyway.
109 // Poison all shadow memory for a single global.
110 static void PoisonGlobalAndRedzones(const Global *g) {
111 CHECK(asan_inited);
112 CHECK(flags()->check_initialization_order);
113 CHECK(AddrIsInMem(g->beg));
114 CHECK(AddrIsAlignedByGranularity(g->beg));
115 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
116 if (flags()->report_globals >= 3)
117 Printf("DynInitPoison : %s\n", g->name);
118 PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
121 static void UnpoisonGlobal(const Global *g) {
122 CHECK(asan_inited);
123 CHECK(flags()->check_initialization_order);
124 CHECK(AddrIsInMem(g->beg));
125 CHECK(AddrIsAlignedByGranularity(g->beg));
126 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
127 if (flags()->report_globals >= 3)
128 Printf("DynInitUnpoison: %s\n", g->name);
129 PoisonShadow(g->beg, g->size_with_redzone, 0);
130 PoisonRedZones(*g);
133 } // namespace __asan
135 // ---------------------- Interface ---------------- {{{1
136 using namespace __asan; // NOLINT
138 // Register an array of globals.
139 void __asan_register_globals(__asan_global *globals, uptr n) {
140 if (!flags()->report_globals) return;
141 BlockingMutexLock lock(&mu_for_globals);
142 for (uptr i = 0; i < n; i++) {
143 RegisterGlobal(&globals[i]);
147 // Unregister an array of globals.
148 // We must do this when a shared objects gets dlclosed.
149 void __asan_unregister_globals(__asan_global *globals, uptr n) {
150 if (!flags()->report_globals) return;
151 BlockingMutexLock lock(&mu_for_globals);
152 for (uptr i = 0; i < n; i++) {
153 UnregisterGlobal(&globals[i]);
157 // This method runs immediately prior to dynamic initialization in each TU,
158 // when all dynamically initialized globals are unpoisoned. This method
159 // poisons all global variables not defined in this TU, so that a dynamic
160 // initializer can only touch global variables in the same TU.
161 void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) {
162 if (!flags()->check_initialization_order) return;
163 CHECK(list_of_dynamic_init_globals);
164 BlockingMutexLock lock(&mu_for_globals);
165 bool from_current_tu = false;
166 // The list looks like:
167 // a => ... => b => last_addr => ... => first_addr => c => ...
168 // The globals of the current TU reside between last_addr and first_addr.
169 for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
170 if (l->g->beg == last_addr)
171 from_current_tu = true;
172 if (!from_current_tu)
173 PoisonGlobalAndRedzones(l->g);
174 if (l->g->beg == first_addr)
175 from_current_tu = false;
177 CHECK(!from_current_tu);
180 // This method runs immediately after dynamic initialization in each TU, when
181 // all dynamically initialized globals except for those defined in the current
182 // TU are poisoned. It simply unpoisons all dynamically initialized globals.
183 void __asan_after_dynamic_init() {
184 if (!flags()->check_initialization_order) return;
185 BlockingMutexLock lock(&mu_for_globals);
186 for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
187 UnpoisonGlobal(l->g);