asan_globals.cc revision 05e16a028d26503153a8fe512a500676cad66031
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===-- asan_globals.cc ---------------------------------------------------===//
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                     The LLVM Compiler Infrastructure
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// License. See LICENSE.TXT for details.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===//
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is a part of AddressSanitizer, an address sanity checker.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handle globals.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===//
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "asan_interceptors.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "asan_internal.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "asan_mapping.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "asan_report.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "asan_stack.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "asan_stats.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "asan_thread.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_common/sanitizer_mutex.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace __asan {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef __asan_global Global;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ListOfGlobals {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Global *g;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListOfGlobals *next;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static LowLevelAllocator allocator_for_globals;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ListOfGlobals *list_of_all_globals;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ListOfGlobals *list_of_dynamic_init_globals;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void PoisonRedZones(const Global &g) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               kAsanGlobalRedzoneMagic);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g.size != aligned_size) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // partial right redzone
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PoisonShadowPartialRightRedzone(
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        g.size % SHADOW_GRANULARITY,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SHADOW_GRANULARITY,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kAsanGlobalRedzoneMagic);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ReportGlobal(const Global &g, const char *prefix) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         g.module_name, g.has_dynamic_init);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DescribeAddressIfGlobal(uptr addr, uptr size) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!flags()->report_globals) return false;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BlockingMutexLock lock(&mu_for_globals);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool res = false;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Global &g = *l->g;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (flags()->report_globals >= 2)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportGlobal(g, "Search");
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    res |= DescribeAddressRelativeToGlobal(addr, size, g);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return res;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Register a global variable.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function may be called more than once for every global
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so we store the globals in a map.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void RegisterGlobal(const Global *g) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(asan_inited);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flags()->report_globals >= 2)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportGlobal(*g, "Added");
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(flags()->report_globals);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsInMem(g->beg));
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsAlignedByGranularity(g->beg));
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PoisonRedZones(*g);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListOfGlobals *l =
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  l->g = g;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  l->next = list_of_all_globals;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  list_of_all_globals = l;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g->has_dynamic_init) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    l->g = g;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    l->next = list_of_dynamic_init_globals;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    list_of_dynamic_init_globals = l;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void UnregisterGlobal(const Global *g) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(asan_inited);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(flags()->report_globals);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsInMem(g->beg));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsAlignedByGranularity(g->beg));
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PoisonShadow(g->beg, g->size_with_redzone, 0);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We unpoison the shadow memory for the global but we do not remove it from
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the list because that would require O(n^2) time with the current list
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // implementation. It might not be worth doing anyway.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Poison all shadow memory for a single global.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void PoisonGlobalAndRedzones(const Global *g) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(asan_inited);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(flags()->check_initialization_order);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsInMem(g->beg));
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsAlignedByGranularity(g->beg));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flags()->report_globals >= 3)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Printf("DynInitPoison  : %s\n", g->name);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void UnpoisonGlobal(const Global *g) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(asan_inited);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(flags()->check_initialization_order);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsInMem(g->beg));
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsAlignedByGranularity(g->beg));
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (flags()->report_globals >= 3)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Printf("DynInitUnpoison: %s\n", g->name);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PoisonShadow(g->beg, g->size_with_redzone, 0);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PoisonRedZones(*g);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace __asan
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---------------------- Interface ---------------- {{{1
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace __asan;  // NOLINT
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Register an array of globals.
137void __asan_register_globals(__asan_global *globals, uptr n) {
138  if (!flags()->report_globals) return;
139  BlockingMutexLock lock(&mu_for_globals);
140  for (uptr i = 0; i < n; i++) {
141    RegisterGlobal(&globals[i]);
142  }
143}
144
145// Unregister an array of globals.
146// We must do this when a shared objects gets dlclosed.
147void __asan_unregister_globals(__asan_global *globals, uptr n) {
148  if (!flags()->report_globals) return;
149  BlockingMutexLock lock(&mu_for_globals);
150  for (uptr i = 0; i < n; i++) {
151    UnregisterGlobal(&globals[i]);
152  }
153}
154
155// This method runs immediately prior to dynamic initialization in each TU,
156// when all dynamically initialized globals are unpoisoned.  This method
157// poisons all global variables not defined in this TU, so that a dynamic
158// initializer can only touch global variables in the same TU.
159void __asan_before_dynamic_init(const char *module_name) {
160  if (!flags()->check_initialization_order) return;
161  CHECK(list_of_dynamic_init_globals);
162  CHECK(module_name);
163  BlockingMutexLock lock(&mu_for_globals);
164  for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
165    if (l->g->module_name != module_name)
166      PoisonGlobalAndRedzones(l->g);
167  }
168}
169
170// This method runs immediately after dynamic initialization in each TU, when
171// all dynamically initialized globals except for those defined in the current
172// TU are poisoned.  It simply unpoisons all dynamically initialized globals.
173void __asan_after_dynamic_init() {
174  if (!flags()->check_initialization_order) return;
175  BlockingMutexLock lock(&mu_for_globals);
176  for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
177    UnpoisonGlobal(l->g);
178}
179