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