]> git.ipfire.org Git - thirdparty/gcc.git/blame - libsanitizer/asan/asan_globals.cc
re PR fortran/56052 ([OOP] ICE in omp_add_variable, at gimplify.c:5606)
[thirdparty/gcc.git] / libsanitizer / asan / asan_globals.cc
CommitLineData
f35db108
WM
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"
21
22namespace __asan {
23
24typedef __asan_global Global;
25
26struct ListOfGlobals {
27 const Global *g;
28 ListOfGlobals *next;
29};
30
31static AsanLock mu_for_globals(LINKER_INITIALIZED);
32static LowLevelAllocator allocator_for_globals;
33static ListOfGlobals *list_of_all_globals;
34static ListOfGlobals *list_of_dynamic_init_globals;
35
36void 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);
53 }
54}
55
56static uptr GetAlignedSize(uptr size) {
57 return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone)
58 * kGlobalAndStackRedzone;
59}
60
61bool 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);
71 }
72 return res;
73}
74
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.
78static 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;
99 }
100}
101
102static 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.
112}
113
114// Poison all shadow memory for a single global.
115static 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);
124}
125
126static 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);
136}
137
138} // namespace __asan
139
140// ---------------------- Interface ---------------- {{{1
141using namespace __asan; // NOLINT
142
143// Register one global with a default redzone.
144void __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);
154}
155
156// Register an array of globals.
157void __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]);
162 }
163}
164
165// Unregister an array of globals.
166// We must do this when a shared objects gets dlclosed.
167void __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]);
172 }
173}
174
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.
179void __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;
194 }
195 CHECK(!from_current_tu);
196}
197
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.
201void __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);
206}