xref: /netbsd-src/external/gpl3/gcc.old/dist/libsanitizer/asan/asan_globals.cc (revision 212397c69a103ae7e5eafa8731ddfae671d2dee7)
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_common/sanitizer_mutex.h"
20 
21 namespace __asan {
22 
23 typedef __asan_global Global;
24 
25 struct ListOfGlobals {
26   const Global *g;
27   ListOfGlobals *next;
28 };
29 
30 static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
31 static LowLevelAllocator allocator_for_globals;
32 static ListOfGlobals *list_of_all_globals;
33 static ListOfGlobals *list_of_dynamic_init_globals;
34 
35 void PoisonRedZones(const Global &g)  {
36   uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
37   PoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
38                kAsanGlobalRedzoneMagic);
39   if (g.size != aligned_size) {
40     // partial right redzone
41     PoisonShadowPartialRightRedzone(
42         g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
43         g.size % SHADOW_GRANULARITY,
44         SHADOW_GRANULARITY,
45         kAsanGlobalRedzoneMagic);
46   }
47 }
48 
49 bool DescribeAddressIfGlobal(uptr addr, uptr size) {
50   if (!flags()->report_globals) return false;
51   BlockingMutexLock lock(&mu_for_globals);
52   bool res = false;
53   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
54     const Global &g = *l->g;
55     if (flags()->report_globals >= 2)
56       Report("Search Global: beg=%p size=%zu name=%s\n",
57              (void*)g.beg, g.size, (char*)g.name);
58     res |= DescribeAddressRelativeToGlobal(addr, size, g);
59   }
60   return res;
61 }
62 
63 // Register a global variable.
64 // This function may be called more than once for every global
65 // so we store the globals in a map.
66 static void RegisterGlobal(const Global *g) {
67   CHECK(asan_inited);
68   if (flags()->report_globals >= 2)
69     Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n",
70            (void*)g->beg, g->size, g->size_with_redzone, g->name,
71            g->has_dynamic_init);
72   CHECK(flags()->report_globals);
73   CHECK(AddrIsInMem(g->beg));
74   CHECK(AddrIsAlignedByGranularity(g->beg));
75   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
76   PoisonRedZones(*g);
77   ListOfGlobals *l =
78       (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
79   l->g = g;
80   l->next = list_of_all_globals;
81   list_of_all_globals = l;
82   if (g->has_dynamic_init) {
83     l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
84     l->g = g;
85     l->next = list_of_dynamic_init_globals;
86     list_of_dynamic_init_globals = l;
87   }
88 }
89 
90 static void UnregisterGlobal(const Global *g) {
91   CHECK(asan_inited);
92   CHECK(flags()->report_globals);
93   CHECK(AddrIsInMem(g->beg));
94   CHECK(AddrIsAlignedByGranularity(g->beg));
95   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
96   PoisonShadow(g->beg, g->size_with_redzone, 0);
97   // We unpoison the shadow memory for the global but we do not remove it from
98   // the list because that would require O(n^2) time with the current list
99   // implementation. It might not be worth doing anyway.
100 }
101 
102 // Poison all shadow memory for a single global.
103 static void PoisonGlobalAndRedzones(const Global *g) {
104   CHECK(asan_inited);
105   CHECK(flags()->check_initialization_order);
106   CHECK(AddrIsInMem(g->beg));
107   CHECK(AddrIsAlignedByGranularity(g->beg));
108   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
109   if (flags()->report_globals >= 3)
110     Printf("DynInitPoison  : %s\n", g->name);
111   PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
112 }
113 
114 static void UnpoisonGlobal(const Global *g) {
115   CHECK(asan_inited);
116   CHECK(flags()->check_initialization_order);
117   CHECK(AddrIsInMem(g->beg));
118   CHECK(AddrIsAlignedByGranularity(g->beg));
119   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
120   if (flags()->report_globals >= 3)
121     Printf("DynInitUnpoison: %s\n", g->name);
122   PoisonShadow(g->beg, g->size_with_redzone, 0);
123   PoisonRedZones(*g);
124 }
125 
126 }  // namespace __asan
127 
128 // ---------------------- Interface ---------------- {{{1
129 using namespace __asan;  // NOLINT
130 
131 // Register an array of globals.
132 void __asan_register_globals(__asan_global *globals, uptr n) {
133   if (!flags()->report_globals) return;
134   BlockingMutexLock lock(&mu_for_globals);
135   for (uptr i = 0; i < n; i++) {
136     RegisterGlobal(&globals[i]);
137   }
138 }
139 
140 // Unregister an array of globals.
141 // We must do this when a shared objects gets dlclosed.
142 void __asan_unregister_globals(__asan_global *globals, uptr n) {
143   if (!flags()->report_globals) return;
144   BlockingMutexLock lock(&mu_for_globals);
145   for (uptr i = 0; i < n; i++) {
146     UnregisterGlobal(&globals[i]);
147   }
148 }
149 
150 // This method runs immediately prior to dynamic initialization in each TU,
151 // when all dynamically initialized globals are unpoisoned.  This method
152 // poisons all global variables not defined in this TU, so that a dynamic
153 // initializer can only touch global variables in the same TU.
154 void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) {
155   if (!flags()->check_initialization_order) return;
156   CHECK(list_of_dynamic_init_globals);
157   BlockingMutexLock lock(&mu_for_globals);
158   bool from_current_tu = false;
159   // The list looks like:
160   // a => ... => b => last_addr => ... => first_addr => c => ...
161   // The globals of the current TU reside between last_addr and first_addr.
162   for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
163     if (l->g->beg == last_addr)
164       from_current_tu = true;
165     if (!from_current_tu)
166       PoisonGlobalAndRedzones(l->g);
167     if (l->g->beg == first_addr)
168       from_current_tu = false;
169   }
170   CHECK(!from_current_tu);
171 }
172 
173 // This method runs immediately after dynamic initialization in each TU, when
174 // all dynamically initialized globals except for those defined in the current
175 // TU are poisoned.  It simply unpoisons all dynamically initialized globals.
176 void __asan_after_dynamic_init() {
177   if (!flags()->check_initialization_order) return;
178   BlockingMutexLock lock(&mu_for_globals);
179   for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
180     UnpoisonGlobal(l->g);
181 }
182