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