xref: /aosp_15_r20/external/compiler-rt/lib/asan/asan_globals.cc (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //===-- asan_globals.cc ---------------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot //                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of AddressSanitizer, an address sanity checker.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot // Handle globals.
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot 
15*7c3d14c8STreehugger Robot #include "asan_interceptors.h"
16*7c3d14c8STreehugger Robot #include "asan_internal.h"
17*7c3d14c8STreehugger Robot #include "asan_mapping.h"
18*7c3d14c8STreehugger Robot #include "asan_poisoning.h"
19*7c3d14c8STreehugger Robot #include "asan_report.h"
20*7c3d14c8STreehugger Robot #include "asan_stack.h"
21*7c3d14c8STreehugger Robot #include "asan_stats.h"
22*7c3d14c8STreehugger Robot #include "asan_suppressions.h"
23*7c3d14c8STreehugger Robot #include "asan_thread.h"
24*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common.h"
25*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_mutex.h"
26*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_placement_new.h"
27*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_stackdepot.h"
28*7c3d14c8STreehugger Robot 
29*7c3d14c8STreehugger Robot namespace __asan {
30*7c3d14c8STreehugger Robot 
31*7c3d14c8STreehugger Robot typedef __asan_global Global;
32*7c3d14c8STreehugger Robot 
33*7c3d14c8STreehugger Robot struct ListOfGlobals {
34*7c3d14c8STreehugger Robot   const Global *g;
35*7c3d14c8STreehugger Robot   ListOfGlobals *next;
36*7c3d14c8STreehugger Robot };
37*7c3d14c8STreehugger Robot 
38*7c3d14c8STreehugger Robot static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
39*7c3d14c8STreehugger Robot static LowLevelAllocator allocator_for_globals;
40*7c3d14c8STreehugger Robot static ListOfGlobals *list_of_all_globals;
41*7c3d14c8STreehugger Robot 
42*7c3d14c8STreehugger Robot static const int kDynamicInitGlobalsInitialCapacity = 512;
43*7c3d14c8STreehugger Robot struct DynInitGlobal {
44*7c3d14c8STreehugger Robot   Global g;
45*7c3d14c8STreehugger Robot   bool initialized;
46*7c3d14c8STreehugger Robot };
47*7c3d14c8STreehugger Robot typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
48*7c3d14c8STreehugger Robot // Lazy-initialized and never deleted.
49*7c3d14c8STreehugger Robot static VectorOfGlobals *dynamic_init_globals;
50*7c3d14c8STreehugger Robot 
51*7c3d14c8STreehugger Robot // We want to remember where a certain range of globals was registered.
52*7c3d14c8STreehugger Robot struct GlobalRegistrationSite {
53*7c3d14c8STreehugger Robot   u32 stack_id;
54*7c3d14c8STreehugger Robot   Global *g_first, *g_last;
55*7c3d14c8STreehugger Robot };
56*7c3d14c8STreehugger Robot typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
57*7c3d14c8STreehugger Robot static GlobalRegistrationSiteVector *global_registration_site_vector;
58*7c3d14c8STreehugger Robot 
PoisonShadowForGlobal(const Global * g,u8 value)59*7c3d14c8STreehugger Robot ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
60*7c3d14c8STreehugger Robot   FastPoisonShadow(g->beg, g->size_with_redzone, value);
61*7c3d14c8STreehugger Robot }
62*7c3d14c8STreehugger Robot 
PoisonRedZones(const Global & g)63*7c3d14c8STreehugger Robot ALWAYS_INLINE void PoisonRedZones(const Global &g) {
64*7c3d14c8STreehugger Robot   uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
65*7c3d14c8STreehugger Robot   FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
66*7c3d14c8STreehugger Robot                    kAsanGlobalRedzoneMagic);
67*7c3d14c8STreehugger Robot   if (g.size != aligned_size) {
68*7c3d14c8STreehugger Robot     FastPoisonShadowPartialRightRedzone(
69*7c3d14c8STreehugger Robot         g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
70*7c3d14c8STreehugger Robot         g.size % SHADOW_GRANULARITY,
71*7c3d14c8STreehugger Robot         SHADOW_GRANULARITY,
72*7c3d14c8STreehugger Robot         kAsanGlobalRedzoneMagic);
73*7c3d14c8STreehugger Robot   }
74*7c3d14c8STreehugger Robot }
75*7c3d14c8STreehugger Robot 
76*7c3d14c8STreehugger Robot const uptr kMinimalDistanceFromAnotherGlobal = 64;
77*7c3d14c8STreehugger Robot 
IsAddressNearGlobal(uptr addr,const __asan_global & g)78*7c3d14c8STreehugger Robot static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
79*7c3d14c8STreehugger Robot   if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
80*7c3d14c8STreehugger Robot   if (addr >= g.beg + g.size_with_redzone) return false;
81*7c3d14c8STreehugger Robot   return true;
82*7c3d14c8STreehugger Robot }
83*7c3d14c8STreehugger Robot 
ReportGlobal(const Global & g,const char * prefix)84*7c3d14c8STreehugger Robot static void ReportGlobal(const Global &g, const char *prefix) {
85*7c3d14c8STreehugger Robot   Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
86*7c3d14c8STreehugger Robot          prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
87*7c3d14c8STreehugger Robot          g.module_name, g.has_dynamic_init);
88*7c3d14c8STreehugger Robot   if (g.location) {
89*7c3d14c8STreehugger Robot     Report("  location (%p): name=%s[%p], %d %d\n", g.location,
90*7c3d14c8STreehugger Robot            g.location->filename, g.location->filename, g.location->line_no,
91*7c3d14c8STreehugger Robot            g.location->column_no);
92*7c3d14c8STreehugger Robot   }
93*7c3d14c8STreehugger Robot }
94*7c3d14c8STreehugger Robot 
FindRegistrationSite(const Global * g)95*7c3d14c8STreehugger Robot static u32 FindRegistrationSite(const Global *g) {
96*7c3d14c8STreehugger Robot   mu_for_globals.CheckLocked();
97*7c3d14c8STreehugger Robot   CHECK(global_registration_site_vector);
98*7c3d14c8STreehugger Robot   for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
99*7c3d14c8STreehugger Robot     GlobalRegistrationSite &grs = (*global_registration_site_vector)[i];
100*7c3d14c8STreehugger Robot     if (g >= grs.g_first && g <= grs.g_last)
101*7c3d14c8STreehugger Robot       return grs.stack_id;
102*7c3d14c8STreehugger Robot   }
103*7c3d14c8STreehugger Robot   return 0;
104*7c3d14c8STreehugger Robot }
105*7c3d14c8STreehugger Robot 
GetGlobalsForAddress(uptr addr,Global * globals,u32 * reg_sites,int max_globals)106*7c3d14c8STreehugger Robot int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites,
107*7c3d14c8STreehugger Robot                          int max_globals) {
108*7c3d14c8STreehugger Robot   if (!flags()->report_globals) return 0;
109*7c3d14c8STreehugger Robot   BlockingMutexLock lock(&mu_for_globals);
110*7c3d14c8STreehugger Robot   int res = 0;
111*7c3d14c8STreehugger Robot   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
112*7c3d14c8STreehugger Robot     const Global &g = *l->g;
113*7c3d14c8STreehugger Robot     if (flags()->report_globals >= 2)
114*7c3d14c8STreehugger Robot       ReportGlobal(g, "Search");
115*7c3d14c8STreehugger Robot     if (IsAddressNearGlobal(addr, g)) {
116*7c3d14c8STreehugger Robot       globals[res] = g;
117*7c3d14c8STreehugger Robot       if (reg_sites)
118*7c3d14c8STreehugger Robot         reg_sites[res] = FindRegistrationSite(&g);
119*7c3d14c8STreehugger Robot       res++;
120*7c3d14c8STreehugger Robot       if (res == max_globals) break;
121*7c3d14c8STreehugger Robot     }
122*7c3d14c8STreehugger Robot   }
123*7c3d14c8STreehugger Robot   return res;
124*7c3d14c8STreehugger Robot }
125*7c3d14c8STreehugger Robot 
GetInfoForAddressIfGlobal(uptr addr,AddressDescription * descr)126*7c3d14c8STreehugger Robot bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
127*7c3d14c8STreehugger Robot   Global g = {};
128*7c3d14c8STreehugger Robot   if (GetGlobalsForAddress(addr, &g, nullptr, 1)) {
129*7c3d14c8STreehugger Robot     internal_strncpy(descr->name, g.name, descr->name_size);
130*7c3d14c8STreehugger Robot     descr->region_address = g.beg;
131*7c3d14c8STreehugger Robot     descr->region_size = g.size;
132*7c3d14c8STreehugger Robot     descr->region_kind = "global";
133*7c3d14c8STreehugger Robot     return true;
134*7c3d14c8STreehugger Robot   }
135*7c3d14c8STreehugger Robot   return false;
136*7c3d14c8STreehugger Robot }
137*7c3d14c8STreehugger Robot 
138*7c3d14c8STreehugger Robot enum GlobalSymbolState {
139*7c3d14c8STreehugger Robot   UNREGISTERED = 0,
140*7c3d14c8STreehugger Robot   REGISTERED = 1
141*7c3d14c8STreehugger Robot };
142*7c3d14c8STreehugger Robot 
143*7c3d14c8STreehugger Robot // Check ODR violation for given global G via special ODR indicator. We use
144*7c3d14c8STreehugger Robot // this method in case compiler instruments global variables through their
145*7c3d14c8STreehugger Robot // local aliases.
CheckODRViolationViaIndicator(const Global * g)146*7c3d14c8STreehugger Robot static void CheckODRViolationViaIndicator(const Global *g) {
147*7c3d14c8STreehugger Robot   u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
148*7c3d14c8STreehugger Robot   if (*odr_indicator == UNREGISTERED) {
149*7c3d14c8STreehugger Robot     *odr_indicator = REGISTERED;
150*7c3d14c8STreehugger Robot     return;
151*7c3d14c8STreehugger Robot   }
152*7c3d14c8STreehugger Robot   // If *odr_indicator is DEFINED, some module have already registered
153*7c3d14c8STreehugger Robot   // externally visible symbol with the same name. This is an ODR violation.
154*7c3d14c8STreehugger Robot   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
155*7c3d14c8STreehugger Robot     if (g->odr_indicator == l->g->odr_indicator &&
156*7c3d14c8STreehugger Robot         (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
157*7c3d14c8STreehugger Robot         !IsODRViolationSuppressed(g->name))
158*7c3d14c8STreehugger Robot       ReportODRViolation(g, FindRegistrationSite(g),
159*7c3d14c8STreehugger Robot                          l->g, FindRegistrationSite(l->g));
160*7c3d14c8STreehugger Robot   }
161*7c3d14c8STreehugger Robot }
162*7c3d14c8STreehugger Robot 
163*7c3d14c8STreehugger Robot // Check ODR violation for given global G by checking if it's already poisoned.
164*7c3d14c8STreehugger Robot // We use this method in case compiler doesn't use private aliases for global
165*7c3d14c8STreehugger Robot // variables.
CheckODRViolationViaPoisoning(const Global * g)166*7c3d14c8STreehugger Robot static void CheckODRViolationViaPoisoning(const Global *g) {
167*7c3d14c8STreehugger Robot   if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
168*7c3d14c8STreehugger Robot     // This check may not be enough: if the first global is much larger
169*7c3d14c8STreehugger Robot     // the entire redzone of the second global may be within the first global.
170*7c3d14c8STreehugger Robot     for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
171*7c3d14c8STreehugger Robot       if (g->beg == l->g->beg &&
172*7c3d14c8STreehugger Robot           (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
173*7c3d14c8STreehugger Robot           !IsODRViolationSuppressed(g->name))
174*7c3d14c8STreehugger Robot         ReportODRViolation(g, FindRegistrationSite(g),
175*7c3d14c8STreehugger Robot                            l->g, FindRegistrationSite(l->g));
176*7c3d14c8STreehugger Robot     }
177*7c3d14c8STreehugger Robot   }
178*7c3d14c8STreehugger Robot }
179*7c3d14c8STreehugger Robot 
180*7c3d14c8STreehugger Robot // Clang provides two different ways for global variables protection:
181*7c3d14c8STreehugger Robot // it can poison the global itself or its private alias. In former
182*7c3d14c8STreehugger Robot // case we may poison same symbol multiple times, that can help us to
183*7c3d14c8STreehugger Robot // cheaply detect ODR violation: if we try to poison an already poisoned
184*7c3d14c8STreehugger Robot // global, we have ODR violation error.
185*7c3d14c8STreehugger Robot // In latter case, we poison each symbol exactly once, so we use special
186*7c3d14c8STreehugger Robot // indicator symbol to perform similar check.
187*7c3d14c8STreehugger Robot // In either case, compiler provides a special odr_indicator field to Global
188*7c3d14c8STreehugger Robot // structure, that can contain two kinds of values:
189*7c3d14c8STreehugger Robot //   1) Non-zero value. In this case, odr_indicator is an address of
190*7c3d14c8STreehugger Robot //      corresponding indicator variable for given global.
191*7c3d14c8STreehugger Robot //   2) Zero. This means that we don't use private aliases for global variables
192*7c3d14c8STreehugger Robot //      and can freely check ODR violation with the first method.
193*7c3d14c8STreehugger Robot //
194*7c3d14c8STreehugger Robot // This routine chooses between two different methods of ODR violation
195*7c3d14c8STreehugger Robot // detection.
UseODRIndicator(const Global * g)196*7c3d14c8STreehugger Robot static inline bool UseODRIndicator(const Global *g) {
197*7c3d14c8STreehugger Robot   // Use ODR indicator method iff use_odr_indicator flag is set and
198*7c3d14c8STreehugger Robot   // indicator symbol address is not 0.
199*7c3d14c8STreehugger Robot   return flags()->use_odr_indicator && g->odr_indicator > 0;
200*7c3d14c8STreehugger Robot }
201*7c3d14c8STreehugger Robot 
202*7c3d14c8STreehugger Robot // Register a global variable.
203*7c3d14c8STreehugger Robot // This function may be called more than once for every global
204*7c3d14c8STreehugger Robot // so we store the globals in a map.
RegisterGlobal(const Global * g)205*7c3d14c8STreehugger Robot static void RegisterGlobal(const Global *g) {
206*7c3d14c8STreehugger Robot   CHECK(asan_inited);
207*7c3d14c8STreehugger Robot   if (flags()->report_globals >= 2)
208*7c3d14c8STreehugger Robot     ReportGlobal(*g, "Added");
209*7c3d14c8STreehugger Robot   CHECK(flags()->report_globals);
210*7c3d14c8STreehugger Robot   CHECK(AddrIsInMem(g->beg));
211*7c3d14c8STreehugger Robot   if (!AddrIsAlignedByGranularity(g->beg)) {
212*7c3d14c8STreehugger Robot     Report("The following global variable is not properly aligned.\n");
213*7c3d14c8STreehugger Robot     Report("This may happen if another global with the same name\n");
214*7c3d14c8STreehugger Robot     Report("resides in another non-instrumented module.\n");
215*7c3d14c8STreehugger Robot     Report("Or the global comes from a C file built w/o -fno-common.\n");
216*7c3d14c8STreehugger Robot     Report("In either case this is likely an ODR violation bug,\n");
217*7c3d14c8STreehugger Robot     Report("but AddressSanitizer can not provide more details.\n");
218*7c3d14c8STreehugger Robot     ReportODRViolation(g, FindRegistrationSite(g), g, FindRegistrationSite(g));
219*7c3d14c8STreehugger Robot     CHECK(AddrIsAlignedByGranularity(g->beg));
220*7c3d14c8STreehugger Robot   }
221*7c3d14c8STreehugger Robot   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
222*7c3d14c8STreehugger Robot   if (flags()->detect_odr_violation) {
223*7c3d14c8STreehugger Robot     // Try detecting ODR (One Definition Rule) violation, i.e. the situation
224*7c3d14c8STreehugger Robot     // where two globals with the same name are defined in different modules.
225*7c3d14c8STreehugger Robot     if (UseODRIndicator(g))
226*7c3d14c8STreehugger Robot       CheckODRViolationViaIndicator(g);
227*7c3d14c8STreehugger Robot     else
228*7c3d14c8STreehugger Robot       CheckODRViolationViaPoisoning(g);
229*7c3d14c8STreehugger Robot   }
230*7c3d14c8STreehugger Robot   if (CanPoisonMemory())
231*7c3d14c8STreehugger Robot     PoisonRedZones(*g);
232*7c3d14c8STreehugger Robot   ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
233*7c3d14c8STreehugger Robot   l->g = g;
234*7c3d14c8STreehugger Robot   l->next = list_of_all_globals;
235*7c3d14c8STreehugger Robot   list_of_all_globals = l;
236*7c3d14c8STreehugger Robot   if (g->has_dynamic_init) {
237*7c3d14c8STreehugger Robot     if (!dynamic_init_globals) {
238*7c3d14c8STreehugger Robot       dynamic_init_globals = new(allocator_for_globals)
239*7c3d14c8STreehugger Robot           VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
240*7c3d14c8STreehugger Robot     }
241*7c3d14c8STreehugger Robot     DynInitGlobal dyn_global = { *g, false };
242*7c3d14c8STreehugger Robot     dynamic_init_globals->push_back(dyn_global);
243*7c3d14c8STreehugger Robot   }
244*7c3d14c8STreehugger Robot }
245*7c3d14c8STreehugger Robot 
UnregisterGlobal(const Global * g)246*7c3d14c8STreehugger Robot static void UnregisterGlobal(const Global *g) {
247*7c3d14c8STreehugger Robot   CHECK(asan_inited);
248*7c3d14c8STreehugger Robot   if (flags()->report_globals >= 2)
249*7c3d14c8STreehugger Robot     ReportGlobal(*g, "Removed");
250*7c3d14c8STreehugger Robot   CHECK(flags()->report_globals);
251*7c3d14c8STreehugger Robot   CHECK(AddrIsInMem(g->beg));
252*7c3d14c8STreehugger Robot   CHECK(AddrIsAlignedByGranularity(g->beg));
253*7c3d14c8STreehugger Robot   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
254*7c3d14c8STreehugger Robot   if (CanPoisonMemory())
255*7c3d14c8STreehugger Robot     PoisonShadowForGlobal(g, 0);
256*7c3d14c8STreehugger Robot   // We unpoison the shadow memory for the global but we do not remove it from
257*7c3d14c8STreehugger Robot   // the list because that would require O(n^2) time with the current list
258*7c3d14c8STreehugger Robot   // implementation. It might not be worth doing anyway.
259*7c3d14c8STreehugger Robot 
260*7c3d14c8STreehugger Robot   // Release ODR indicator.
261*7c3d14c8STreehugger Robot   if (UseODRIndicator(g)) {
262*7c3d14c8STreehugger Robot     u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
263*7c3d14c8STreehugger Robot     *odr_indicator = UNREGISTERED;
264*7c3d14c8STreehugger Robot   }
265*7c3d14c8STreehugger Robot }
266*7c3d14c8STreehugger Robot 
StopInitOrderChecking()267*7c3d14c8STreehugger Robot void StopInitOrderChecking() {
268*7c3d14c8STreehugger Robot   BlockingMutexLock lock(&mu_for_globals);
269*7c3d14c8STreehugger Robot   if (!flags()->check_initialization_order || !dynamic_init_globals)
270*7c3d14c8STreehugger Robot     return;
271*7c3d14c8STreehugger Robot   flags()->check_initialization_order = false;
272*7c3d14c8STreehugger Robot   for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
273*7c3d14c8STreehugger Robot     DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
274*7c3d14c8STreehugger Robot     const Global *g = &dyn_g.g;
275*7c3d14c8STreehugger Robot     // Unpoison the whole global.
276*7c3d14c8STreehugger Robot     PoisonShadowForGlobal(g, 0);
277*7c3d14c8STreehugger Robot     // Poison redzones back.
278*7c3d14c8STreehugger Robot     PoisonRedZones(*g);
279*7c3d14c8STreehugger Robot   }
280*7c3d14c8STreehugger Robot }
281*7c3d14c8STreehugger Robot 
282*7c3d14c8STreehugger Robot } // namespace __asan
283*7c3d14c8STreehugger Robot 
284*7c3d14c8STreehugger Robot // ---------------------- Interface ---------------- {{{1
285*7c3d14c8STreehugger Robot using namespace __asan;  // NOLINT
286*7c3d14c8STreehugger Robot 
287*7c3d14c8STreehugger Robot 
288*7c3d14c8STreehugger Robot // Apply __asan_register_globals to all globals found in the same loaded
289*7c3d14c8STreehugger Robot // executable or shared library as `flag'. The flag tracks whether globals have
290*7c3d14c8STreehugger Robot // already been registered or not for this image.
__asan_register_image_globals(uptr * flag)291*7c3d14c8STreehugger Robot void __asan_register_image_globals(uptr *flag) {
292*7c3d14c8STreehugger Robot   if (*flag)
293*7c3d14c8STreehugger Robot     return;
294*7c3d14c8STreehugger Robot   AsanApplyToGlobals(__asan_register_globals, flag);
295*7c3d14c8STreehugger Robot   *flag = 1;
296*7c3d14c8STreehugger Robot }
297*7c3d14c8STreehugger Robot 
298*7c3d14c8STreehugger Robot // This mirrors __asan_register_image_globals.
__asan_unregister_image_globals(uptr * flag)299*7c3d14c8STreehugger Robot void __asan_unregister_image_globals(uptr *flag) {
300*7c3d14c8STreehugger Robot   if (!*flag)
301*7c3d14c8STreehugger Robot     return;
302*7c3d14c8STreehugger Robot   AsanApplyToGlobals(__asan_unregister_globals, flag);
303*7c3d14c8STreehugger Robot   *flag = 0;
304*7c3d14c8STreehugger Robot }
305*7c3d14c8STreehugger Robot 
306*7c3d14c8STreehugger Robot // Register an array of globals.
__asan_register_globals(__asan_global * globals,uptr n)307*7c3d14c8STreehugger Robot void __asan_register_globals(__asan_global *globals, uptr n) {
308*7c3d14c8STreehugger Robot   if (!flags()->report_globals) return;
309*7c3d14c8STreehugger Robot   GET_STACK_TRACE_MALLOC;
310*7c3d14c8STreehugger Robot   u32 stack_id = StackDepotPut(stack);
311*7c3d14c8STreehugger Robot   BlockingMutexLock lock(&mu_for_globals);
312*7c3d14c8STreehugger Robot   if (!global_registration_site_vector)
313*7c3d14c8STreehugger Robot     global_registration_site_vector =
314*7c3d14c8STreehugger Robot         new(allocator_for_globals) GlobalRegistrationSiteVector(128);
315*7c3d14c8STreehugger Robot   GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};
316*7c3d14c8STreehugger Robot   global_registration_site_vector->push_back(site);
317*7c3d14c8STreehugger Robot   if (flags()->report_globals >= 2) {
318*7c3d14c8STreehugger Robot     PRINT_CURRENT_STACK();
319*7c3d14c8STreehugger Robot     Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
320*7c3d14c8STreehugger Robot   }
321*7c3d14c8STreehugger Robot   for (uptr i = 0; i < n; i++) {
322*7c3d14c8STreehugger Robot     RegisterGlobal(&globals[i]);
323*7c3d14c8STreehugger Robot   }
324*7c3d14c8STreehugger Robot }
325*7c3d14c8STreehugger Robot 
326*7c3d14c8STreehugger Robot // Unregister an array of globals.
327*7c3d14c8STreehugger Robot // We must do this when a shared objects gets dlclosed.
__asan_unregister_globals(__asan_global * globals,uptr n)328*7c3d14c8STreehugger Robot void __asan_unregister_globals(__asan_global *globals, uptr n) {
329*7c3d14c8STreehugger Robot   if (!flags()->report_globals) return;
330*7c3d14c8STreehugger Robot   BlockingMutexLock lock(&mu_for_globals);
331*7c3d14c8STreehugger Robot   for (uptr i = 0; i < n; i++) {
332*7c3d14c8STreehugger Robot     UnregisterGlobal(&globals[i]);
333*7c3d14c8STreehugger Robot   }
334*7c3d14c8STreehugger Robot }
335*7c3d14c8STreehugger Robot 
336*7c3d14c8STreehugger Robot // This method runs immediately prior to dynamic initialization in each TU,
337*7c3d14c8STreehugger Robot // when all dynamically initialized globals are unpoisoned.  This method
338*7c3d14c8STreehugger Robot // poisons all global variables not defined in this TU, so that a dynamic
339*7c3d14c8STreehugger Robot // initializer can only touch global variables in the same TU.
__asan_before_dynamic_init(const char * module_name)340*7c3d14c8STreehugger Robot void __asan_before_dynamic_init(const char *module_name) {
341*7c3d14c8STreehugger Robot   if (!flags()->check_initialization_order ||
342*7c3d14c8STreehugger Robot       !CanPoisonMemory())
343*7c3d14c8STreehugger Robot     return;
344*7c3d14c8STreehugger Robot   bool strict_init_order = flags()->strict_init_order;
345*7c3d14c8STreehugger Robot   CHECK(dynamic_init_globals);
346*7c3d14c8STreehugger Robot   CHECK(module_name);
347*7c3d14c8STreehugger Robot   CHECK(asan_inited);
348*7c3d14c8STreehugger Robot   BlockingMutexLock lock(&mu_for_globals);
349*7c3d14c8STreehugger Robot   if (flags()->report_globals >= 3)
350*7c3d14c8STreehugger Robot     Printf("DynInitPoison module: %s\n", module_name);
351*7c3d14c8STreehugger Robot   for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
352*7c3d14c8STreehugger Robot     DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
353*7c3d14c8STreehugger Robot     const Global *g = &dyn_g.g;
354*7c3d14c8STreehugger Robot     if (dyn_g.initialized)
355*7c3d14c8STreehugger Robot       continue;
356*7c3d14c8STreehugger Robot     if (g->module_name != module_name)
357*7c3d14c8STreehugger Robot       PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
358*7c3d14c8STreehugger Robot     else if (!strict_init_order)
359*7c3d14c8STreehugger Robot       dyn_g.initialized = true;
360*7c3d14c8STreehugger Robot   }
361*7c3d14c8STreehugger Robot }
362*7c3d14c8STreehugger Robot 
363*7c3d14c8STreehugger Robot // This method runs immediately after dynamic initialization in each TU, when
364*7c3d14c8STreehugger Robot // all dynamically initialized globals except for those defined in the current
365*7c3d14c8STreehugger Robot // TU are poisoned.  It simply unpoisons all dynamically initialized globals.
__asan_after_dynamic_init()366*7c3d14c8STreehugger Robot void __asan_after_dynamic_init() {
367*7c3d14c8STreehugger Robot   if (!flags()->check_initialization_order ||
368*7c3d14c8STreehugger Robot       !CanPoisonMemory())
369*7c3d14c8STreehugger Robot     return;
370*7c3d14c8STreehugger Robot   CHECK(asan_inited);
371*7c3d14c8STreehugger Robot   BlockingMutexLock lock(&mu_for_globals);
372*7c3d14c8STreehugger Robot   // FIXME: Optionally report that we're unpoisoning globals from a module.
373*7c3d14c8STreehugger Robot   for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
374*7c3d14c8STreehugger Robot     DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
375*7c3d14c8STreehugger Robot     const Global *g = &dyn_g.g;
376*7c3d14c8STreehugger Robot     if (!dyn_g.initialized) {
377*7c3d14c8STreehugger Robot       // Unpoison the whole global.
378*7c3d14c8STreehugger Robot       PoisonShadowForGlobal(g, 0);
379*7c3d14c8STreehugger Robot       // Poison redzones back.
380*7c3d14c8STreehugger Robot       PoisonRedZones(*g);
381*7c3d14c8STreehugger Robot     }
382*7c3d14c8STreehugger Robot   }
383*7c3d14c8STreehugger Robot }
384