diff options
Diffstat (limited to 'lib/asan/asan_globals.cc')
-rw-r--r-- | lib/asan/asan_globals.cc | 151 |
1 files changed, 85 insertions, 66 deletions
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index f8c4040b8e869..4e18bb8e23552 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -12,15 +12,14 @@ // Handle globals. //===----------------------------------------------------------------------===// #include "asan_interceptors.h" -#include "asan_interface.h" #include "asan_internal.h" -#include "asan_lock.h" #include "asan_mapping.h" +#include "asan_report.h" #include "asan_stack.h" #include "asan_stats.h" #include "asan_thread.h" - -#include <ctype.h> +#include "sanitizer/asan_interface.h" +#include "sanitizer_common/sanitizer_mutex.h" namespace __asan { @@ -31,9 +30,10 @@ struct ListOfGlobals { ListOfGlobals *next; }; -static AsanLock mu_for_globals(LINKER_INITIALIZED); -static ListOfGlobals *list_of_globals; -static LowLevelAllocator allocator_for_globals(LINKER_INITIALIZED); +static BlockingMutex mu_for_globals(LINKER_INITIALIZED); +static LowLevelAllocator allocator_for_globals; +static ListOfGlobals *list_of_all_globals; +static ListOfGlobals *list_of_dynamic_init_globals; void PoisonRedZones(const Global &g) { uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE; @@ -55,48 +55,16 @@ void PoisonRedZones(const Global &g) { } } -static uptr GetAlignedSize(uptr size) { - return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone) - * kGlobalAndStackRedzone; -} - - // Check if the global is a zero-terminated ASCII string. If so, print it. -void PrintIfASCII(const Global &g) { - for (uptr p = g.beg; p < g.beg + g.size - 1; p++) { - if (!isascii(*(char*)p)) return; - } - if (*(char*)(g.beg + g.size - 1) != 0) return; - AsanPrintf(" '%s' is ascii string '%s'\n", g.name, (char*)g.beg); -} - -bool DescribeAddrIfMyRedZone(const Global &g, uptr addr) { - if (addr < g.beg - kGlobalAndStackRedzone) return false; - if (addr >= g.beg + g.size_with_redzone) return false; - AsanPrintf("%p is located ", (void*)addr); - if (addr < g.beg) { - AsanPrintf("%zd bytes to the left", g.beg - addr); - } else if (addr >= g.beg + g.size) { - AsanPrintf("%zd bytes to the right", addr - (g.beg + g.size)); - } else { - AsanPrintf("%zd bytes inside", addr - g.beg); // Can it happen? - } - AsanPrintf(" of global variable '%s' (0x%zx) of size %zu\n", - g.name, g.beg, g.size); - PrintIfASCII(g); - return true; -} - - -bool DescribeAddrIfGlobal(uptr addr) { +bool DescribeAddressIfGlobal(uptr addr) { if (!flags()->report_globals) return false; - ScopedLock lock(&mu_for_globals); + BlockingMutexLock lock(&mu_for_globals); bool res = false; - for (ListOfGlobals *l = list_of_globals; l; l = l->next) { + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { const Global &g = *l->g; if (flags()->report_globals >= 2) - AsanPrintf("Search Global: beg=%p size=%zu name=%s\n", - (void*)g.beg, g.size, (char*)g.name); - res |= DescribeAddrIfMyRedZone(g, addr); + Report("Search Global: beg=%p size=%zu name=%s\n", + (void*)g.beg, g.size, (char*)g.name); + res |= DescribeAddressRelativeToGlobal(addr, g); } return res; } @@ -106,6 +74,10 @@ bool DescribeAddrIfGlobal(uptr addr) { // so we store the globals in a map. static void RegisterGlobal(const Global *g) { CHECK(asan_inited); + if (flags()->report_globals >= 2) + Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n", + (void*)g->beg, g->size, g->size_with_redzone, g->name, + g->has_dynamic_init); CHECK(flags()->report_globals); CHECK(AddrIsInMem(g->beg)); CHECK(AddrIsAlignedByGranularity(g->beg)); @@ -114,11 +86,14 @@ static void RegisterGlobal(const Global *g) { ListOfGlobals *l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals)); l->g = g; - l->next = list_of_globals; - list_of_globals = l; - if (flags()->report_globals >= 2) - Report("Added Global: beg=%p size=%zu name=%s\n", - (void*)g->beg, g->size, g->name); + l->next = list_of_all_globals; + list_of_all_globals = l; + if (g->has_dynamic_init) { + l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals)); + l->g = g; + l->next = list_of_dynamic_init_globals; + list_of_dynamic_init_globals = l; + } } static void UnregisterGlobal(const Global *g) { @@ -133,39 +108,83 @@ static void UnregisterGlobal(const Global *g) { // implementation. It might not be worth doing anyway. } +// Poison all shadow memory for a single global. +static void PoisonGlobalAndRedzones(const Global *g) { + CHECK(asan_inited); + CHECK(flags()->check_initialization_order); + CHECK(AddrIsInMem(g->beg)); + CHECK(AddrIsAlignedByGranularity(g->beg)); + CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); + if (flags()->report_globals >= 3) + Printf("DynInitPoison : %s\n", g->name); + PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic); +} + +static void UnpoisonGlobal(const Global *g) { + CHECK(asan_inited); + CHECK(flags()->check_initialization_order); + CHECK(AddrIsInMem(g->beg)); + CHECK(AddrIsAlignedByGranularity(g->beg)); + CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); + if (flags()->report_globals >= 3) + Printf("DynInitUnpoison: %s\n", g->name); + PoisonShadow(g->beg, g->size_with_redzone, 0); + PoisonRedZones(*g); +} + } // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT -// Register one global with a default redzone. -void __asan_register_global(uptr addr, uptr size, - const char *name) { - if (!flags()->report_globals) return; - ScopedLock lock(&mu_for_globals); - Global *g = (Global *)allocator_for_globals.Allocate(sizeof(Global)); - g->beg = addr; - g->size = size; - g->size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone; - g->name = name; - RegisterGlobal(g); -} - // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; - ScopedLock lock(&mu_for_globals); + BlockingMutexLock lock(&mu_for_globals); for (uptr i = 0; i < n; i++) { RegisterGlobal(&globals[i]); } } // Unregister an array of globals. -// We must do it when a shared objects gets dlclosed. +// We must do this when a shared objects gets dlclosed. void __asan_unregister_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; - ScopedLock lock(&mu_for_globals); + BlockingMutexLock lock(&mu_for_globals); for (uptr i = 0; i < n; i++) { UnregisterGlobal(&globals[i]); } } + +// This method runs immediately prior to dynamic initialization in each TU, +// when all dynamically initialized globals are unpoisoned. This method +// poisons all global variables not defined in this TU, so that a dynamic +// initializer can only touch global variables in the same TU. +void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) { + if (!flags()->check_initialization_order) return; + CHECK(list_of_dynamic_init_globals); + BlockingMutexLock lock(&mu_for_globals); + bool from_current_tu = false; + // The list looks like: + // a => ... => b => last_addr => ... => first_addr => c => ... + // The globals of the current TU reside between last_addr and first_addr. + for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) { + if (l->g->beg == last_addr) + from_current_tu = true; + if (!from_current_tu) + PoisonGlobalAndRedzones(l->g); + if (l->g->beg == first_addr) + from_current_tu = false; + } + CHECK(!from_current_tu); +} + +// This method runs immediately after dynamic initialization in each TU, when +// all dynamically initialized globals except for those defined in the current +// TU are poisoned. It simply unpoisons all dynamically initialized globals. +void __asan_after_dynamic_init() { + if (!flags()->check_initialization_order) return; + BlockingMutexLock lock(&mu_for_globals); + for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) + UnpoisonGlobal(l->g); +} |