xref: /openbsd-src/gnu/llvm/compiler-rt/lib/asan/asan_globals.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- asan_globals.cpp --------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of AddressSanitizer, an address sanity checker.
103cab2bb3Spatrick //
113cab2bb3Spatrick // Handle globals.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick 
143cab2bb3Spatrick #include "asan_interceptors.h"
153cab2bb3Spatrick #include "asan_internal.h"
163cab2bb3Spatrick #include "asan_mapping.h"
173cab2bb3Spatrick #include "asan_poisoning.h"
183cab2bb3Spatrick #include "asan_report.h"
193cab2bb3Spatrick #include "asan_stack.h"
203cab2bb3Spatrick #include "asan_stats.h"
213cab2bb3Spatrick #include "asan_suppressions.h"
223cab2bb3Spatrick #include "asan_thread.h"
233cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
243cab2bb3Spatrick #include "sanitizer_common/sanitizer_mutex.h"
253cab2bb3Spatrick #include "sanitizer_common/sanitizer_placement_new.h"
263cab2bb3Spatrick #include "sanitizer_common/sanitizer_stackdepot.h"
273cab2bb3Spatrick #include "sanitizer_common/sanitizer_symbolizer.h"
283cab2bb3Spatrick 
293cab2bb3Spatrick namespace __asan {
303cab2bb3Spatrick 
313cab2bb3Spatrick typedef __asan_global Global;
323cab2bb3Spatrick 
333cab2bb3Spatrick struct ListOfGlobals {
343cab2bb3Spatrick   const Global *g;
353cab2bb3Spatrick   ListOfGlobals *next;
363cab2bb3Spatrick };
373cab2bb3Spatrick 
38*810390e3Srobert static Mutex mu_for_globals;
393cab2bb3Spatrick static LowLevelAllocator allocator_for_globals;
403cab2bb3Spatrick static ListOfGlobals *list_of_all_globals;
413cab2bb3Spatrick 
423cab2bb3Spatrick static const int kDynamicInitGlobalsInitialCapacity = 512;
433cab2bb3Spatrick struct DynInitGlobal {
443cab2bb3Spatrick   Global g;
453cab2bb3Spatrick   bool initialized;
463cab2bb3Spatrick };
473cab2bb3Spatrick typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
483cab2bb3Spatrick // Lazy-initialized and never deleted.
493cab2bb3Spatrick static VectorOfGlobals *dynamic_init_globals;
503cab2bb3Spatrick 
513cab2bb3Spatrick // We want to remember where a certain range of globals was registered.
523cab2bb3Spatrick struct GlobalRegistrationSite {
533cab2bb3Spatrick   u32 stack_id;
543cab2bb3Spatrick   Global *g_first, *g_last;
553cab2bb3Spatrick };
563cab2bb3Spatrick typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
573cab2bb3Spatrick static GlobalRegistrationSiteVector *global_registration_site_vector;
583cab2bb3Spatrick 
PoisonShadowForGlobal(const Global * g,u8 value)593cab2bb3Spatrick ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
603cab2bb3Spatrick   FastPoisonShadow(g->beg, g->size_with_redzone, value);
613cab2bb3Spatrick }
623cab2bb3Spatrick 
PoisonRedZones(const Global & g)633cab2bb3Spatrick ALWAYS_INLINE void PoisonRedZones(const Global &g) {
64*810390e3Srobert   uptr aligned_size = RoundUpTo(g.size, ASAN_SHADOW_GRANULARITY);
653cab2bb3Spatrick   FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
663cab2bb3Spatrick                    kAsanGlobalRedzoneMagic);
673cab2bb3Spatrick   if (g.size != aligned_size) {
683cab2bb3Spatrick     FastPoisonShadowPartialRightRedzone(
69*810390e3Srobert         g.beg + RoundDownTo(g.size, ASAN_SHADOW_GRANULARITY),
70*810390e3Srobert         g.size % ASAN_SHADOW_GRANULARITY, ASAN_SHADOW_GRANULARITY,
713cab2bb3Spatrick         kAsanGlobalRedzoneMagic);
723cab2bb3Spatrick   }
733cab2bb3Spatrick }
743cab2bb3Spatrick 
753cab2bb3Spatrick const uptr kMinimalDistanceFromAnotherGlobal = 64;
763cab2bb3Spatrick 
IsAddressNearGlobal(uptr addr,const __asan_global & g)773cab2bb3Spatrick static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
783cab2bb3Spatrick   if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
793cab2bb3Spatrick   if (addr >= g.beg + g.size_with_redzone) return false;
803cab2bb3Spatrick   return true;
813cab2bb3Spatrick }
823cab2bb3Spatrick 
ReportGlobal(const Global & g,const char * prefix)833cab2bb3Spatrick static void ReportGlobal(const Global &g, const char *prefix) {
843cab2bb3Spatrick   Report(
853cab2bb3Spatrick       "%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu "
863cab2bb3Spatrick       "odr_indicator=%p\n",
87*810390e3Srobert       prefix, (void *)&g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
883cab2bb3Spatrick       g.module_name, g.has_dynamic_init, (void *)g.odr_indicator);
89*810390e3Srobert 
90*810390e3Srobert   DataInfo info;
91*810390e3Srobert   Symbolizer::GetOrInit()->SymbolizeData(g.beg, &info);
92*810390e3Srobert   if (info.line != 0) {
93*810390e3Srobert     Report("  location: name=%s, %d\n", info.file, static_cast<int>(info.line));
943cab2bb3Spatrick   }
953cab2bb3Spatrick }
963cab2bb3Spatrick 
FindRegistrationSite(const Global * g)973cab2bb3Spatrick static u32 FindRegistrationSite(const Global *g) {
983cab2bb3Spatrick   mu_for_globals.CheckLocked();
993cab2bb3Spatrick   CHECK(global_registration_site_vector);
1003cab2bb3Spatrick   for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
1013cab2bb3Spatrick     GlobalRegistrationSite &grs = (*global_registration_site_vector)[i];
1023cab2bb3Spatrick     if (g >= grs.g_first && g <= grs.g_last)
1033cab2bb3Spatrick       return grs.stack_id;
1043cab2bb3Spatrick   }
1053cab2bb3Spatrick   return 0;
1063cab2bb3Spatrick }
1073cab2bb3Spatrick 
GetGlobalsForAddress(uptr addr,Global * globals,u32 * reg_sites,int max_globals)1083cab2bb3Spatrick int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites,
1093cab2bb3Spatrick                          int max_globals) {
1103cab2bb3Spatrick   if (!flags()->report_globals) return 0;
111*810390e3Srobert   Lock lock(&mu_for_globals);
1123cab2bb3Spatrick   int res = 0;
1133cab2bb3Spatrick   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
1143cab2bb3Spatrick     const Global &g = *l->g;
1153cab2bb3Spatrick     if (flags()->report_globals >= 2)
1163cab2bb3Spatrick       ReportGlobal(g, "Search");
1173cab2bb3Spatrick     if (IsAddressNearGlobal(addr, g)) {
1183cab2bb3Spatrick       internal_memcpy(&globals[res], &g, sizeof(g));
1193cab2bb3Spatrick       if (reg_sites)
1203cab2bb3Spatrick         reg_sites[res] = FindRegistrationSite(&g);
1213cab2bb3Spatrick       res++;
1223cab2bb3Spatrick       if (res == max_globals)
1233cab2bb3Spatrick         break;
1243cab2bb3Spatrick     }
1253cab2bb3Spatrick   }
1263cab2bb3Spatrick   return res;
1273cab2bb3Spatrick }
1283cab2bb3Spatrick 
1293cab2bb3Spatrick enum GlobalSymbolState {
1303cab2bb3Spatrick   UNREGISTERED = 0,
1313cab2bb3Spatrick   REGISTERED = 1
1323cab2bb3Spatrick };
1333cab2bb3Spatrick 
1343cab2bb3Spatrick // Check ODR violation for given global G via special ODR indicator. We use
1353cab2bb3Spatrick // this method in case compiler instruments global variables through their
1363cab2bb3Spatrick // local aliases.
CheckODRViolationViaIndicator(const Global * g)1373cab2bb3Spatrick static void CheckODRViolationViaIndicator(const Global *g) {
1383cab2bb3Spatrick   // Instrumentation requests to skip ODR check.
1393cab2bb3Spatrick   if (g->odr_indicator == UINTPTR_MAX)
1403cab2bb3Spatrick     return;
1413cab2bb3Spatrick   u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
1423cab2bb3Spatrick   if (*odr_indicator == UNREGISTERED) {
1433cab2bb3Spatrick     *odr_indicator = REGISTERED;
1443cab2bb3Spatrick     return;
1453cab2bb3Spatrick   }
1463cab2bb3Spatrick   // If *odr_indicator is DEFINED, some module have already registered
1473cab2bb3Spatrick   // externally visible symbol with the same name. This is an ODR violation.
1483cab2bb3Spatrick   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
1493cab2bb3Spatrick     if (g->odr_indicator == l->g->odr_indicator &&
1503cab2bb3Spatrick         (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
1513cab2bb3Spatrick         !IsODRViolationSuppressed(g->name))
1523cab2bb3Spatrick       ReportODRViolation(g, FindRegistrationSite(g),
1533cab2bb3Spatrick                          l->g, FindRegistrationSite(l->g));
1543cab2bb3Spatrick   }
1553cab2bb3Spatrick }
1563cab2bb3Spatrick 
1573cab2bb3Spatrick // Check ODR violation for given global G by checking if it's already poisoned.
1583cab2bb3Spatrick // We use this method in case compiler doesn't use private aliases for global
1593cab2bb3Spatrick // variables.
CheckODRViolationViaPoisoning(const Global * g)1603cab2bb3Spatrick static void CheckODRViolationViaPoisoning(const Global *g) {
1613cab2bb3Spatrick   if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
1623cab2bb3Spatrick     // This check may not be enough: if the first global is much larger
1633cab2bb3Spatrick     // the entire redzone of the second global may be within the first global.
1643cab2bb3Spatrick     for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
1653cab2bb3Spatrick       if (g->beg == l->g->beg &&
1663cab2bb3Spatrick           (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
1673cab2bb3Spatrick           !IsODRViolationSuppressed(g->name))
1683cab2bb3Spatrick         ReportODRViolation(g, FindRegistrationSite(g),
1693cab2bb3Spatrick                            l->g, FindRegistrationSite(l->g));
1703cab2bb3Spatrick     }
1713cab2bb3Spatrick   }
1723cab2bb3Spatrick }
1733cab2bb3Spatrick 
1743cab2bb3Spatrick // Clang provides two different ways for global variables protection:
1753cab2bb3Spatrick // it can poison the global itself or its private alias. In former
1763cab2bb3Spatrick // case we may poison same symbol multiple times, that can help us to
1773cab2bb3Spatrick // cheaply detect ODR violation: if we try to poison an already poisoned
1783cab2bb3Spatrick // global, we have ODR violation error.
1793cab2bb3Spatrick // In latter case, we poison each symbol exactly once, so we use special
1803cab2bb3Spatrick // indicator symbol to perform similar check.
1813cab2bb3Spatrick // In either case, compiler provides a special odr_indicator field to Global
1823cab2bb3Spatrick // structure, that can contain two kinds of values:
1833cab2bb3Spatrick //   1) Non-zero value. In this case, odr_indicator is an address of
1843cab2bb3Spatrick //      corresponding indicator variable for given global.
1853cab2bb3Spatrick //   2) Zero. This means that we don't use private aliases for global variables
1863cab2bb3Spatrick //      and can freely check ODR violation with the first method.
1873cab2bb3Spatrick //
1883cab2bb3Spatrick // This routine chooses between two different methods of ODR violation
1893cab2bb3Spatrick // detection.
UseODRIndicator(const Global * g)1903cab2bb3Spatrick static inline bool UseODRIndicator(const Global *g) {
1913cab2bb3Spatrick   return g->odr_indicator > 0;
1923cab2bb3Spatrick }
1933cab2bb3Spatrick 
1943cab2bb3Spatrick // Register a global variable.
1953cab2bb3Spatrick // This function may be called more than once for every global
1963cab2bb3Spatrick // so we store the globals in a map.
RegisterGlobal(const Global * g)1973cab2bb3Spatrick static void RegisterGlobal(const Global *g) {
1983cab2bb3Spatrick   CHECK(asan_inited);
1993cab2bb3Spatrick   if (flags()->report_globals >= 2)
2003cab2bb3Spatrick     ReportGlobal(*g, "Added");
2013cab2bb3Spatrick   CHECK(flags()->report_globals);
2023cab2bb3Spatrick   CHECK(AddrIsInMem(g->beg));
2033cab2bb3Spatrick   if (!AddrIsAlignedByGranularity(g->beg)) {
2043cab2bb3Spatrick     Report("The following global variable is not properly aligned.\n");
2053cab2bb3Spatrick     Report("This may happen if another global with the same name\n");
2063cab2bb3Spatrick     Report("resides in another non-instrumented module.\n");
2073cab2bb3Spatrick     Report("Or the global comes from a C file built w/o -fno-common.\n");
2083cab2bb3Spatrick     Report("In either case this is likely an ODR violation bug,\n");
2093cab2bb3Spatrick     Report("but AddressSanitizer can not provide more details.\n");
2103cab2bb3Spatrick     ReportODRViolation(g, FindRegistrationSite(g), g, FindRegistrationSite(g));
2113cab2bb3Spatrick     CHECK(AddrIsAlignedByGranularity(g->beg));
2123cab2bb3Spatrick   }
2133cab2bb3Spatrick   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
2143cab2bb3Spatrick   if (flags()->detect_odr_violation) {
2153cab2bb3Spatrick     // Try detecting ODR (One Definition Rule) violation, i.e. the situation
2163cab2bb3Spatrick     // where two globals with the same name are defined in different modules.
2173cab2bb3Spatrick     if (UseODRIndicator(g))
2183cab2bb3Spatrick       CheckODRViolationViaIndicator(g);
2193cab2bb3Spatrick     else
2203cab2bb3Spatrick       CheckODRViolationViaPoisoning(g);
2213cab2bb3Spatrick   }
2223cab2bb3Spatrick   if (CanPoisonMemory())
2233cab2bb3Spatrick     PoisonRedZones(*g);
2243cab2bb3Spatrick   ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
2253cab2bb3Spatrick   l->g = g;
2263cab2bb3Spatrick   l->next = list_of_all_globals;
2273cab2bb3Spatrick   list_of_all_globals = l;
2283cab2bb3Spatrick   if (g->has_dynamic_init) {
2293cab2bb3Spatrick     if (!dynamic_init_globals) {
2303cab2bb3Spatrick       dynamic_init_globals = new (allocator_for_globals) VectorOfGlobals;
2313cab2bb3Spatrick       dynamic_init_globals->reserve(kDynamicInitGlobalsInitialCapacity);
2323cab2bb3Spatrick     }
2333cab2bb3Spatrick     DynInitGlobal dyn_global = { *g, false };
2343cab2bb3Spatrick     dynamic_init_globals->push_back(dyn_global);
2353cab2bb3Spatrick   }
2363cab2bb3Spatrick }
2373cab2bb3Spatrick 
UnregisterGlobal(const Global * g)2383cab2bb3Spatrick static void UnregisterGlobal(const Global *g) {
2393cab2bb3Spatrick   CHECK(asan_inited);
2403cab2bb3Spatrick   if (flags()->report_globals >= 2)
2413cab2bb3Spatrick     ReportGlobal(*g, "Removed");
2423cab2bb3Spatrick   CHECK(flags()->report_globals);
2433cab2bb3Spatrick   CHECK(AddrIsInMem(g->beg));
2443cab2bb3Spatrick   CHECK(AddrIsAlignedByGranularity(g->beg));
2453cab2bb3Spatrick   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
2463cab2bb3Spatrick   if (CanPoisonMemory())
2473cab2bb3Spatrick     PoisonShadowForGlobal(g, 0);
2483cab2bb3Spatrick   // We unpoison the shadow memory for the global but we do not remove it from
2493cab2bb3Spatrick   // the list because that would require O(n^2) time with the current list
2503cab2bb3Spatrick   // implementation. It might not be worth doing anyway.
2513cab2bb3Spatrick 
2523cab2bb3Spatrick   // Release ODR indicator.
2533cab2bb3Spatrick   if (UseODRIndicator(g) && g->odr_indicator != UINTPTR_MAX) {
2543cab2bb3Spatrick     u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
2553cab2bb3Spatrick     *odr_indicator = UNREGISTERED;
2563cab2bb3Spatrick   }
2573cab2bb3Spatrick }
2583cab2bb3Spatrick 
StopInitOrderChecking()2593cab2bb3Spatrick void StopInitOrderChecking() {
260*810390e3Srobert   Lock lock(&mu_for_globals);
2613cab2bb3Spatrick   if (!flags()->check_initialization_order || !dynamic_init_globals)
2623cab2bb3Spatrick     return;
2633cab2bb3Spatrick   flags()->check_initialization_order = false;
2643cab2bb3Spatrick   for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
2653cab2bb3Spatrick     DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
2663cab2bb3Spatrick     const Global *g = &dyn_g.g;
2673cab2bb3Spatrick     // Unpoison the whole global.
2683cab2bb3Spatrick     PoisonShadowForGlobal(g, 0);
2693cab2bb3Spatrick     // Poison redzones back.
2703cab2bb3Spatrick     PoisonRedZones(*g);
2713cab2bb3Spatrick   }
2723cab2bb3Spatrick }
2733cab2bb3Spatrick 
IsASCII(unsigned char c)2743cab2bb3Spatrick static bool IsASCII(unsigned char c) { return /*0x00 <= c &&*/ c <= 0x7F; }
2753cab2bb3Spatrick 
MaybeDemangleGlobalName(const char * name)2763cab2bb3Spatrick const char *MaybeDemangleGlobalName(const char *name) {
2773cab2bb3Spatrick   // We can spoil names of globals with C linkage, so use an heuristic
2783cab2bb3Spatrick   // approach to check if the name should be demangled.
2793cab2bb3Spatrick   bool should_demangle = false;
2803cab2bb3Spatrick   if (name[0] == '_' && name[1] == 'Z')
2813cab2bb3Spatrick     should_demangle = true;
2823cab2bb3Spatrick   else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?')
2833cab2bb3Spatrick     should_demangle = true;
2843cab2bb3Spatrick 
2853cab2bb3Spatrick   return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name;
2863cab2bb3Spatrick }
2873cab2bb3Spatrick 
2883cab2bb3Spatrick // Check if the global is a zero-terminated ASCII string. If so, print it.
PrintGlobalNameIfASCII(InternalScopedString * str,const __asan_global & g)2893cab2bb3Spatrick void PrintGlobalNameIfASCII(InternalScopedString *str, const __asan_global &g) {
2903cab2bb3Spatrick   for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
2913cab2bb3Spatrick     unsigned char c = *(unsigned char *)p;
2923cab2bb3Spatrick     if (c == '\0' || !IsASCII(c)) return;
2933cab2bb3Spatrick   }
2943cab2bb3Spatrick   if (*(char *)(g.beg + g.size - 1) != '\0') return;
2953cab2bb3Spatrick   str->append("  '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name),
2963cab2bb3Spatrick               (char *)g.beg);
2973cab2bb3Spatrick }
2983cab2bb3Spatrick 
PrintGlobalLocation(InternalScopedString * str,const __asan_global & g)2993cab2bb3Spatrick void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g) {
300*810390e3Srobert   DataInfo info;
301*810390e3Srobert   Symbolizer::GetOrInit()->SymbolizeData(g.beg, &info);
302*810390e3Srobert 
303*810390e3Srobert   if (info.line != 0) {
304*810390e3Srobert     str->append("%s:%d", info.file, static_cast<int>(info.line));
305*810390e3Srobert   } else {
306*810390e3Srobert     str->append("%s", g.module_name);
307*810390e3Srobert   }
3083cab2bb3Spatrick }
3093cab2bb3Spatrick 
3103cab2bb3Spatrick } // namespace __asan
3113cab2bb3Spatrick 
3123cab2bb3Spatrick // ---------------------- Interface ---------------- {{{1
3133cab2bb3Spatrick using namespace __asan;
3143cab2bb3Spatrick 
3153cab2bb3Spatrick // Apply __asan_register_globals to all globals found in the same loaded
3163cab2bb3Spatrick // executable or shared library as `flag'. The flag tracks whether globals have
3173cab2bb3Spatrick // already been registered or not for this image.
__asan_register_image_globals(uptr * flag)3183cab2bb3Spatrick void __asan_register_image_globals(uptr *flag) {
3193cab2bb3Spatrick   if (*flag)
3203cab2bb3Spatrick     return;
3213cab2bb3Spatrick   AsanApplyToGlobals(__asan_register_globals, flag);
3223cab2bb3Spatrick   *flag = 1;
3233cab2bb3Spatrick }
3243cab2bb3Spatrick 
3253cab2bb3Spatrick // This mirrors __asan_register_image_globals.
__asan_unregister_image_globals(uptr * flag)3263cab2bb3Spatrick void __asan_unregister_image_globals(uptr *flag) {
3273cab2bb3Spatrick   if (!*flag)
3283cab2bb3Spatrick     return;
3293cab2bb3Spatrick   AsanApplyToGlobals(__asan_unregister_globals, flag);
3303cab2bb3Spatrick   *flag = 0;
3313cab2bb3Spatrick }
3323cab2bb3Spatrick 
__asan_register_elf_globals(uptr * flag,void * start,void * stop)3333cab2bb3Spatrick void __asan_register_elf_globals(uptr *flag, void *start, void *stop) {
3343cab2bb3Spatrick   if (*flag) return;
3353cab2bb3Spatrick   if (!start) return;
3363cab2bb3Spatrick   CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
3373cab2bb3Spatrick   __asan_global *globals_start = (__asan_global*)start;
3383cab2bb3Spatrick   __asan_global *globals_stop = (__asan_global*)stop;
3393cab2bb3Spatrick   __asan_register_globals(globals_start, globals_stop - globals_start);
3403cab2bb3Spatrick   *flag = 1;
3413cab2bb3Spatrick }
3423cab2bb3Spatrick 
__asan_unregister_elf_globals(uptr * flag,void * start,void * stop)3433cab2bb3Spatrick void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) {
3443cab2bb3Spatrick   if (!*flag) return;
3453cab2bb3Spatrick   if (!start) return;
3463cab2bb3Spatrick   CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
3473cab2bb3Spatrick   __asan_global *globals_start = (__asan_global*)start;
3483cab2bb3Spatrick   __asan_global *globals_stop = (__asan_global*)stop;
3493cab2bb3Spatrick   __asan_unregister_globals(globals_start, globals_stop - globals_start);
3503cab2bb3Spatrick   *flag = 0;
3513cab2bb3Spatrick }
3523cab2bb3Spatrick 
3533cab2bb3Spatrick // Register an array of globals.
__asan_register_globals(__asan_global * globals,uptr n)3543cab2bb3Spatrick void __asan_register_globals(__asan_global *globals, uptr n) {
3553cab2bb3Spatrick   if (!flags()->report_globals) return;
3563cab2bb3Spatrick   GET_STACK_TRACE_MALLOC;
3573cab2bb3Spatrick   u32 stack_id = StackDepotPut(stack);
358*810390e3Srobert   Lock lock(&mu_for_globals);
3593cab2bb3Spatrick   if (!global_registration_site_vector) {
3603cab2bb3Spatrick     global_registration_site_vector =
3613cab2bb3Spatrick         new (allocator_for_globals) GlobalRegistrationSiteVector;
3623cab2bb3Spatrick     global_registration_site_vector->reserve(128);
3633cab2bb3Spatrick   }
3643cab2bb3Spatrick   GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};
3653cab2bb3Spatrick   global_registration_site_vector->push_back(site);
3663cab2bb3Spatrick   if (flags()->report_globals >= 2) {
3673cab2bb3Spatrick     PRINT_CURRENT_STACK();
368*810390e3Srobert     Printf("=== ID %d; %p %p\n", stack_id, (void *)&globals[0],
369*810390e3Srobert            (void *)&globals[n - 1]);
3703cab2bb3Spatrick   }
3713cab2bb3Spatrick   for (uptr i = 0; i < n; i++) {
3723cab2bb3Spatrick     if (SANITIZER_WINDOWS && globals[i].beg == 0) {
3733cab2bb3Spatrick       // The MSVC incremental linker may pad globals out to 256 bytes. As long
3743cab2bb3Spatrick       // as __asan_global is less than 256 bytes large and its size is a power
3753cab2bb3Spatrick       // of two, we can skip over the padding.
3763cab2bb3Spatrick       static_assert(
3773cab2bb3Spatrick           sizeof(__asan_global) < 256 &&
3783cab2bb3Spatrick               (sizeof(__asan_global) & (sizeof(__asan_global) - 1)) == 0,
3793cab2bb3Spatrick           "sizeof(__asan_global) incompatible with incremental linker padding");
3803cab2bb3Spatrick       // If these are padding bytes, the rest of the global should be zero.
3813cab2bb3Spatrick       CHECK(globals[i].size == 0 && globals[i].size_with_redzone == 0 &&
3823cab2bb3Spatrick             globals[i].name == nullptr && globals[i].module_name == nullptr &&
3833cab2bb3Spatrick             globals[i].odr_indicator == 0);
3843cab2bb3Spatrick       continue;
3853cab2bb3Spatrick     }
3863cab2bb3Spatrick     RegisterGlobal(&globals[i]);
3873cab2bb3Spatrick   }
3883cab2bb3Spatrick 
3893cab2bb3Spatrick   // Poison the metadata. It should not be accessible to user code.
3903cab2bb3Spatrick   PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global),
3913cab2bb3Spatrick                kAsanGlobalRedzoneMagic);
3923cab2bb3Spatrick }
3933cab2bb3Spatrick 
3943cab2bb3Spatrick // Unregister an array of globals.
3953cab2bb3Spatrick // We must do this when a shared objects gets dlclosed.
__asan_unregister_globals(__asan_global * globals,uptr n)3963cab2bb3Spatrick void __asan_unregister_globals(__asan_global *globals, uptr n) {
3973cab2bb3Spatrick   if (!flags()->report_globals) return;
398*810390e3Srobert   Lock lock(&mu_for_globals);
3993cab2bb3Spatrick   for (uptr i = 0; i < n; i++) {
4003cab2bb3Spatrick     if (SANITIZER_WINDOWS && globals[i].beg == 0) {
4013cab2bb3Spatrick       // Skip globals that look like padding from the MSVC incremental linker.
4023cab2bb3Spatrick       // See comment in __asan_register_globals.
4033cab2bb3Spatrick       continue;
4043cab2bb3Spatrick     }
4053cab2bb3Spatrick     UnregisterGlobal(&globals[i]);
4063cab2bb3Spatrick   }
4073cab2bb3Spatrick 
4083cab2bb3Spatrick   // Unpoison the metadata.
4093cab2bb3Spatrick   PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global), 0);
4103cab2bb3Spatrick }
4113cab2bb3Spatrick 
4123cab2bb3Spatrick // This method runs immediately prior to dynamic initialization in each TU,
4133cab2bb3Spatrick // when all dynamically initialized globals are unpoisoned.  This method
4143cab2bb3Spatrick // poisons all global variables not defined in this TU, so that a dynamic
4153cab2bb3Spatrick // initializer can only touch global variables in the same TU.
__asan_before_dynamic_init(const char * module_name)4163cab2bb3Spatrick void __asan_before_dynamic_init(const char *module_name) {
4173cab2bb3Spatrick   if (!flags()->check_initialization_order ||
4183cab2bb3Spatrick       !CanPoisonMemory() ||
4193cab2bb3Spatrick       !dynamic_init_globals)
4203cab2bb3Spatrick     return;
4213cab2bb3Spatrick   bool strict_init_order = flags()->strict_init_order;
4223cab2bb3Spatrick   CHECK(module_name);
4233cab2bb3Spatrick   CHECK(asan_inited);
424*810390e3Srobert   Lock lock(&mu_for_globals);
4253cab2bb3Spatrick   if (flags()->report_globals >= 3)
4263cab2bb3Spatrick     Printf("DynInitPoison module: %s\n", module_name);
4273cab2bb3Spatrick   for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
4283cab2bb3Spatrick     DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
4293cab2bb3Spatrick     const Global *g = &dyn_g.g;
4303cab2bb3Spatrick     if (dyn_g.initialized)
4313cab2bb3Spatrick       continue;
4323cab2bb3Spatrick     if (g->module_name != module_name)
4333cab2bb3Spatrick       PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
4343cab2bb3Spatrick     else if (!strict_init_order)
4353cab2bb3Spatrick       dyn_g.initialized = true;
4363cab2bb3Spatrick   }
4373cab2bb3Spatrick }
4383cab2bb3Spatrick 
4393cab2bb3Spatrick // This method runs immediately after dynamic initialization in each TU, when
4403cab2bb3Spatrick // all dynamically initialized globals except for those defined in the current
4413cab2bb3Spatrick // TU are poisoned.  It simply unpoisons all dynamically initialized globals.
__asan_after_dynamic_init()4423cab2bb3Spatrick void __asan_after_dynamic_init() {
4433cab2bb3Spatrick   if (!flags()->check_initialization_order ||
4443cab2bb3Spatrick       !CanPoisonMemory() ||
4453cab2bb3Spatrick       !dynamic_init_globals)
4463cab2bb3Spatrick     return;
4473cab2bb3Spatrick   CHECK(asan_inited);
448*810390e3Srobert   Lock lock(&mu_for_globals);
4493cab2bb3Spatrick   // FIXME: Optionally report that we're unpoisoning globals from a module.
4503cab2bb3Spatrick   for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
4513cab2bb3Spatrick     DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
4523cab2bb3Spatrick     const Global *g = &dyn_g.g;
4533cab2bb3Spatrick     if (!dyn_g.initialized) {
4543cab2bb3Spatrick       // Unpoison the whole global.
4553cab2bb3Spatrick       PoisonShadowForGlobal(g, 0);
4563cab2bb3Spatrick       // Poison redzones back.
4573cab2bb3Spatrick       PoisonRedZones(*g);
4583cab2bb3Spatrick     }
4593cab2bb3Spatrick   }
4603cab2bb3Spatrick }
461