1e5f5895bda30f374b0b51412fd4d837fa59aed66Alexey Samsonov//===-- asan_globals.cc ---------------------------------------------------===//
21e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
31e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//                     The LLVM Compiler Infrastructure
41e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
51e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// This file is distributed under the University of Illinois Open Source
61e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// License. See LICENSE.TXT for details.
71e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
81e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//===----------------------------------------------------------------------===//
91e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
101e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// This file is a part of AddressSanitizer, an address sanity checker.
111e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
121e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// Handle globals.
131e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//===----------------------------------------------------------------------===//
141e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_interceptors.h"
151e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_internal.h"
161e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_mapping.h"
177e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov#include "asan_poisoning.h"
18e4bfca2b154a6ab4eda921aff454035f33f3551aAlexey Samsonov#include "asan_report.h"
191e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_stack.h"
201e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_stats.h"
2186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include "asan_suppressions.h"
221e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_thread.h"
237e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov#include "sanitizer_common/sanitizer_common.h"
24f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov#include "sanitizer_common/sanitizer_mutex.h"
257e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov#include "sanitizer_common/sanitizer_placement_new.h"
266a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines#include "sanitizer_common/sanitizer_stackdepot.h"
271e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
281e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanynamespace __asan {
291e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
301e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanytypedef __asan_global Global;
311e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
32b89567ce41bef82cf92a9c741c78b632c07b2781Kostya Serebryanystruct ListOfGlobals {
33b89567ce41bef82cf92a9c741c78b632c07b2781Kostya Serebryany  const Global *g;
34b89567ce41bef82cf92a9c741c78b632c07b2781Kostya Serebryany  ListOfGlobals *next;
35b89567ce41bef82cf92a9c741c78b632c07b2781Kostya Serebryany};
36b89567ce41bef82cf92a9c741c78b632c07b2781Kostya Serebryany
37f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukovstatic BlockingMutex mu_for_globals(LINKER_INITIALIZED);
38947fbd1a073fcd38988c1ec131452e99bb0313f8Alexey Samsonovstatic LowLevelAllocator allocator_for_globals;
393945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryanystatic ListOfGlobals *list_of_all_globals;
401e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
417e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonovstatic const int kDynamicInitGlobalsInitialCapacity = 512;
42dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonovstruct DynInitGlobal {
43dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov  Global g;
44dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov  bool initialized;
45dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov};
46a64d4359902f1f64992aedfe10d8882ae7c66f40Alexey Samsonovtypedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
477e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov// Lazy-initialized and never deleted.
487e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonovstatic VectorOfGlobals *dynamic_init_globals;
497e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov
506a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines// We want to remember where a certain range of globals was registered.
516a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinesstruct GlobalRegistrationSite {
526a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  u32 stack_id;
536a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  Global *g_first, *g_last;
546a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines};
556a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinestypedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
566a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinesstatic GlobalRegistrationSiteVector *global_registration_site_vector;
576a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines
58abfdbdf5bc7e9d202652fe061acd20c14a4d22f4Timur IskhodzhanovALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
597e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  FastPoisonShadow(g->beg, g->size_with_redzone, value);
607e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov}
617e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov
62abfdbdf5bc7e9d202652fe061acd20c14a4d22f4Timur IskhodzhanovALWAYS_INLINE void PoisonRedZones(const Global &g) {
63a3b0e5e4f9f48b2ed0baee10c0236eda7c21c660Kostya Serebryany  uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
647e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
657e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov                   kAsanGlobalRedzoneMagic);
66a3b0e5e4f9f48b2ed0baee10c0236eda7c21c660Kostya Serebryany  if (g.size != aligned_size) {
677e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov    FastPoisonShadowPartialRightRedzone(
68a3b0e5e4f9f48b2ed0baee10c0236eda7c21c660Kostya Serebryany        g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
69a3b0e5e4f9f48b2ed0baee10c0236eda7c21c660Kostya Serebryany        g.size % SHADOW_GRANULARITY,
70a3b0e5e4f9f48b2ed0baee10c0236eda7c21c660Kostya Serebryany        SHADOW_GRANULARITY,
71a3b0e5e4f9f48b2ed0baee10c0236eda7c21c660Kostya Serebryany        kAsanGlobalRedzoneMagic);
721e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  }
731e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
741e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
756d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesconst uptr kMinimalDistanceFromAnotherGlobal = 64;
766d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
776d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesbool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
786d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
796d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (addr >= g.beg + g.size_with_redzone) return false;
806d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return true;
816d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}
826d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
8305e16a028d26503153a8fe512a500676cad66031Alexey Samsonovstatic void ReportGlobal(const Global &g, const char *prefix) {
846a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
856d1862363c88c183b0ed7740fca876342cf0474bStephen Hines         prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
8605e16a028d26503153a8fe512a500676cad66031Alexey Samsonov         g.module_name, g.has_dynamic_init);
876d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (g.location) {
886d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    Report("  location (%p): name=%s[%p], %d %d\n", g.location,
896d1862363c88c183b0ed7740fca876342cf0474bStephen Hines           g.location->filename, g.location->filename, g.location->line_no,
906d1862363c88c183b0ed7740fca876342cf0474bStephen Hines           g.location->column_no);
916d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  }
9205e16a028d26503153a8fe512a500676cad66031Alexey Samsonov}
9305e16a028d26503153a8fe512a500676cad66031Alexey Samsonov
946d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesstatic bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print,
956d1862363c88c183b0ed7740fca876342cf0474bStephen Hines                                      Global *output_global) {
96cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  if (!flags()->report_globals) return false;
97f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  BlockingMutexLock lock(&mu_for_globals);
981e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  bool res = false;
993945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany  for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
100b89567ce41bef82cf92a9c741c78b632c07b2781Kostya Serebryany    const Global &g = *l->g;
1016d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    if (print) {
1026d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      if (flags()->report_globals >= 2)
1036d1862363c88c183b0ed7740fca876342cf0474bStephen Hines        ReportGlobal(g, "Search");
1046d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      res |= DescribeAddressRelativeToGlobal(addr, size, g);
1056d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    } else {
1066d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      if (IsAddressNearGlobal(addr, g)) {
1076d1862363c88c183b0ed7740fca876342cf0474bStephen Hines        CHECK(output_global);
1086d1862363c88c183b0ed7740fca876342cf0474bStephen Hines        *output_global = g;
1096d1862363c88c183b0ed7740fca876342cf0474bStephen Hines        return true;
1106d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      }
1116d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    }
1121e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  }
1131e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  return res;
1141e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
1151e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
1166d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesbool DescribeAddressIfGlobal(uptr addr, uptr size) {
1176d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true,
1186d1862363c88c183b0ed7740fca876342cf0474bStephen Hines                                   /* output_global */ nullptr);
1196d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}
1206d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
1216d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesbool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
1226d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  Global g = {};
1236d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) {
1246d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    internal_strncpy(descr->name, g.name, descr->name_size);
1256d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    descr->region_address = g.beg;
1266d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    descr->region_size = g.size;
1276d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    descr->region_kind = "global";
1286d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    return true;
1296d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  }
1306d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return false;
1316d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}
1326d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
1336a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinesu32 FindRegistrationSite(const Global *g) {
1346a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  CHECK(global_registration_site_vector);
1356a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
1366a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    GlobalRegistrationSite &grs = (*global_registration_site_vector)[i];
1376a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    if (g >= grs.g_first && g <= grs.g_last)
1386a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines      return grs.stack_id;
1396a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  }
1406a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  return 0;
1416a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines}
1426a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines
1431e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// Register a global variable.
1441e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// This function may be called more than once for every global
1451e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// so we store the globals in a map.
1461e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanystatic void RegisterGlobal(const Global *g) {
1471e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  CHECK(asan_inited);
1483945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany  if (flags()->report_globals >= 2)
14905e16a028d26503153a8fe512a500676cad66031Alexey Samsonov    ReportGlobal(*g, "Added");
150cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  CHECK(flags()->report_globals);
1511e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  CHECK(AddrIsInMem(g->beg));
152b89567ce41bef82cf92a9c741c78b632c07b2781Kostya Serebryany  CHECK(AddrIsAlignedByGranularity(g->beg));
153c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
1542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (flags()->detect_odr_violation) {
1552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    // Try detecting ODR (One Definition Rule) violation, i.e. the situation
1562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    // where two globals with the same name are defined in different modules.
1572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
1582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      // This check may not be enough: if the first global is much larger
1592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      // the entire redzone of the second global may be within the first global.
1602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
1612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        if (g->beg == l->g->beg &&
16286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines            (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
16386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines            !IsODRViolationSuppressed(g->name))
1646a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines          ReportODRViolation(g, FindRegistrationSite(g),
1656a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines                             l->g, FindRegistrationSite(l->g));
1662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      }
1672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    }
1682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
16986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (CanPoisonMemory())
1707e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov    PoisonRedZones(*g);
17153177247698bfba075f2d5b255a447fc3ced6976Peter Collingbourne  ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
172b89567ce41bef82cf92a9c741c78b632c07b2781Kostya Serebryany  l->g = g;
1733945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany  l->next = list_of_all_globals;
1743945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany  list_of_all_globals = l;
1753945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany  if (g->has_dynamic_init) {
1767e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov    if (dynamic_init_globals == 0) {
17753177247698bfba075f2d5b255a447fc3ced6976Peter Collingbourne      dynamic_init_globals = new(allocator_for_globals)
1787e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov          VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
1797e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov    }
180dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    DynInitGlobal dyn_global = { *g, false };
181dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    dynamic_init_globals->push_back(dyn_global);
1823945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany  }
1831e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
1841e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
185c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryanystatic void UnregisterGlobal(const Global *g) {
186c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany  CHECK(asan_inited);
18786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (flags()->report_globals >= 2)
18886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    ReportGlobal(*g, "Removed");
189cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  CHECK(flags()->report_globals);
190c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany  CHECK(AddrIsInMem(g->beg));
191c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany  CHECK(AddrIsAlignedByGranularity(g->beg));
192c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
19386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (CanPoisonMemory())
1947e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov    PoisonShadowForGlobal(g, 0);
195c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany  // We unpoison the shadow memory for the global but we do not remove it from
196c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany  // the list because that would require O(n^2) time with the current list
197c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany  // implementation. It might not be worth doing anyway.
198c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany}
199c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany
20046efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonovvoid StopInitOrderChecking() {
20146efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov  BlockingMutexLock lock(&mu_for_globals);
20246efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov  if (!flags()->check_initialization_order || !dynamic_init_globals)
20346efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov    return;
20446efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov  flags()->check_initialization_order = false;
20546efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
20646efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
20746efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov    const Global *g = &dyn_g.g;
20846efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov    // Unpoison the whole global.
20946efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov    PoisonShadowForGlobal(g, 0);
21046efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov    // Poison redzones back.
21146efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov    PoisonRedZones(*g);
21246efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov  }
21346efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov}
21446efcb09dc16b91cb805abea52f3ff6081a63751Alexey Samsonov
2151e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}  // namespace __asan
2161e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
2171e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// ---------------------- Interface ---------------- {{{1
2181e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanyusing namespace __asan;  // NOLINT
2191e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
2201e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// Register an array of globals.
2219aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryanyvoid __asan_register_globals(__asan_global *globals, uptr n) {
222cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  if (!flags()->report_globals) return;
22386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  GET_STACK_TRACE_MALLOC;
2246d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  u32 stack_id = StackDepotPut(stack);
225f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  BlockingMutexLock lock(&mu_for_globals);
2266a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  if (!global_registration_site_vector)
2276a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    global_registration_site_vector =
2286a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines        new(allocator_for_globals) GlobalRegistrationSiteVector(128);
2296a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};
2306a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  global_registration_site_vector->push_back(site);
2316a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  if (flags()->report_globals >= 2) {
2326a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    PRINT_CURRENT_STACK();
2336a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
2346a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  }
2359aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany  for (uptr i = 0; i < n; i++) {
2361e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    RegisterGlobal(&globals[i]);
2371e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  }
2381e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
239c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany
240c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany// Unregister an array of globals.
2413945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany// We must do this when a shared objects gets dlclosed.
2429aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryanyvoid __asan_unregister_globals(__asan_global *globals, uptr n) {
243cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  if (!flags()->report_globals) return;
244f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  BlockingMutexLock lock(&mu_for_globals);
2459aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany  for (uptr i = 0; i < n; i++) {
246c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany    UnregisterGlobal(&globals[i]);
247c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany  }
248c491061eddb0bb7047470b2746cbcbfe7730b2a9Kostya Serebryany}
2493945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany
2503945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany// This method runs immediately prior to dynamic initialization in each TU,
2513945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany// when all dynamically initialized globals are unpoisoned.  This method
2523945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany// poisons all global variables not defined in this TU, so that a dynamic
2533945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany// initializer can only touch global variables in the same TU.
25405e16a028d26503153a8fe512a500676cad66031Alexey Samsonovvoid __asan_before_dynamic_init(const char *module_name) {
2557e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  if (!flags()->check_initialization_order ||
25686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      !CanPoisonMemory())
2577e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov    return;
258dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov  bool strict_init_order = flags()->strict_init_order;
2597e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  CHECK(dynamic_init_globals);
26005e16a028d26503153a8fe512a500676cad66031Alexey Samsonov  CHECK(module_name);
2617e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  CHECK(asan_inited);
262f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  BlockingMutexLock lock(&mu_for_globals);
2637e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  if (flags()->report_globals >= 3)
2647e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov    Printf("DynInitPoison module: %s\n", module_name);
2657e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
266dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
267dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    const Global *g = &dyn_g.g;
268dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    if (dyn_g.initialized)
269dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov      continue;
2707e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov    if (g->module_name != module_name)
2717e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov      PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
272dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    else if (!strict_init_order)
273dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov      dyn_g.initialized = true;
2743945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany  }
2753945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany}
2763945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany
2773945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany// This method runs immediately after dynamic initialization in each TU, when
2783945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany// all dynamically initialized globals except for those defined in the current
2793945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany// TU are poisoned.  It simply unpoisons all dynamically initialized globals.
2803945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryanyvoid __asan_after_dynamic_init() {
2817e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  if (!flags()->check_initialization_order ||
28286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      !CanPoisonMemory())
2837e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov    return;
2847e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  CHECK(asan_inited);
285f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  BlockingMutexLock lock(&mu_for_globals);
2867e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  // FIXME: Optionally report that we're unpoisoning globals from a module.
2877e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
288dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
289dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    const Global *g = &dyn_g.g;
290dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    if (!dyn_g.initialized) {
291dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov      // Unpoison the whole global.
292dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov      PoisonShadowForGlobal(g, 0);
293dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov      // Poison redzones back.
294dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov      PoisonRedZones(*g);
295dfeef67b23ba92bbee598293164ee20078f633a1Alexey Samsonov    }
2967e8434940a1fe7dce531d4c458ccd714da48f609Alexey Samsonov  }
2973945c58f9db42671b1a3b865fde5008f09a3a40eKostya Serebryany}
298