168d75effSDimitry Andric //===-- asan_globals.cpp --------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Handle globals. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 1468d75effSDimitry Andric #include "asan_interceptors.h" 1568d75effSDimitry Andric #include "asan_internal.h" 1668d75effSDimitry Andric #include "asan_mapping.h" 1768d75effSDimitry Andric #include "asan_poisoning.h" 1868d75effSDimitry Andric #include "asan_report.h" 1968d75effSDimitry Andric #include "asan_stack.h" 2068d75effSDimitry Andric #include "asan_stats.h" 2168d75effSDimitry Andric #include "asan_suppressions.h" 2268d75effSDimitry Andric #include "asan_thread.h" 2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_mutex.h" 2568d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 2668d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h" 2768d75effSDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h" 2868d75effSDimitry Andric 2968d75effSDimitry Andric namespace __asan { 3068d75effSDimitry Andric 3168d75effSDimitry Andric typedef __asan_global Global; 3268d75effSDimitry Andric 3368d75effSDimitry Andric struct ListOfGlobals { 3468d75effSDimitry Andric const Global *g; 3568d75effSDimitry Andric ListOfGlobals *next; 3668d75effSDimitry Andric }; 3768d75effSDimitry Andric 38349cc55cSDimitry Andric static Mutex mu_for_globals; 3968d75effSDimitry Andric static ListOfGlobals *list_of_all_globals; 4068d75effSDimitry Andric 4168d75effSDimitry Andric static const int kDynamicInitGlobalsInitialCapacity = 512; 4268d75effSDimitry Andric struct DynInitGlobal { 4368d75effSDimitry Andric Global g; 4468d75effSDimitry Andric bool initialized; 4568d75effSDimitry Andric }; 4668d75effSDimitry Andric typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals; 4768d75effSDimitry Andric // Lazy-initialized and never deleted. 4868d75effSDimitry Andric static VectorOfGlobals *dynamic_init_globals; 4968d75effSDimitry Andric 5068d75effSDimitry Andric // We want to remember where a certain range of globals was registered. 5168d75effSDimitry Andric struct GlobalRegistrationSite { 5268d75effSDimitry Andric u32 stack_id; 5368d75effSDimitry Andric Global *g_first, *g_last; 5468d75effSDimitry Andric }; 5568d75effSDimitry Andric typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector; 5668d75effSDimitry Andric static GlobalRegistrationSiteVector *global_registration_site_vector; 5768d75effSDimitry Andric 5868d75effSDimitry Andric ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) { 5968d75effSDimitry Andric FastPoisonShadow(g->beg, g->size_with_redzone, value); 6068d75effSDimitry Andric } 6168d75effSDimitry Andric 6268d75effSDimitry Andric ALWAYS_INLINE void PoisonRedZones(const Global &g) { 630eae32dcSDimitry Andric uptr aligned_size = RoundUpTo(g.size, ASAN_SHADOW_GRANULARITY); 6468d75effSDimitry Andric FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size, 6568d75effSDimitry Andric kAsanGlobalRedzoneMagic); 6668d75effSDimitry Andric if (g.size != aligned_size) { 6768d75effSDimitry Andric FastPoisonShadowPartialRightRedzone( 680eae32dcSDimitry Andric g.beg + RoundDownTo(g.size, ASAN_SHADOW_GRANULARITY), 690eae32dcSDimitry Andric g.size % ASAN_SHADOW_GRANULARITY, ASAN_SHADOW_GRANULARITY, 7068d75effSDimitry Andric kAsanGlobalRedzoneMagic); 7168d75effSDimitry Andric } 7268d75effSDimitry Andric } 7368d75effSDimitry Andric 7468d75effSDimitry Andric const uptr kMinimalDistanceFromAnotherGlobal = 64; 7568d75effSDimitry Andric 7668d75effSDimitry Andric static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) { 7768d75effSDimitry Andric if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false; 7868d75effSDimitry Andric if (addr >= g.beg + g.size_with_redzone) return false; 7968d75effSDimitry Andric return true; 8068d75effSDimitry Andric } 8168d75effSDimitry Andric 8268d75effSDimitry Andric static void ReportGlobal(const Global &g, const char *prefix) { 835f757f3fSDimitry Andric DataInfo info; 845f757f3fSDimitry Andric bool symbolized = Symbolizer::GetOrInit()->SymbolizeData(g.beg, &info); 8568d75effSDimitry Andric Report( 865f757f3fSDimitry Andric "%s Global[%p]: beg=%p size=%zu/%zu name=%s source=%s module=%s " 875f757f3fSDimitry Andric "dyn_init=%zu " 8868d75effSDimitry Andric "odr_indicator=%p\n", 89349cc55cSDimitry Andric prefix, (void *)&g, (void *)g.beg, g.size, g.size_with_redzone, g.name, 905f757f3fSDimitry Andric g.module_name, (symbolized ? info.module : "?"), g.has_dynamic_init, 915f757f3fSDimitry Andric (void *)g.odr_indicator); 9281ad6265SDimitry Andric 935f757f3fSDimitry Andric if (symbolized && info.line != 0) { 94753f127fSDimitry Andric Report(" location: name=%s, %d\n", info.file, static_cast<int>(info.line)); 955f757f3fSDimitry Andric } else if (g.gcc_location != 0) { 9606c3fb27SDimitry Andric // Fallback to Global::gcc_location 9706c3fb27SDimitry Andric Report(" location: name=%s, %d\n", g.gcc_location->filename, g.gcc_location->line_no); 9806c3fb27SDimitry Andric } 9968d75effSDimitry Andric } 10068d75effSDimitry Andric 10168d75effSDimitry Andric static u32 FindRegistrationSite(const Global *g) { 10268d75effSDimitry Andric mu_for_globals.CheckLocked(); 10368d75effSDimitry Andric CHECK(global_registration_site_vector); 10468d75effSDimitry Andric for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) { 10568d75effSDimitry Andric GlobalRegistrationSite &grs = (*global_registration_site_vector)[i]; 10668d75effSDimitry Andric if (g >= grs.g_first && g <= grs.g_last) 10768d75effSDimitry Andric return grs.stack_id; 10868d75effSDimitry Andric } 10968d75effSDimitry Andric return 0; 11068d75effSDimitry Andric } 11168d75effSDimitry Andric 11268d75effSDimitry Andric int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites, 11368d75effSDimitry Andric int max_globals) { 11468d75effSDimitry Andric if (!flags()->report_globals) return 0; 115349cc55cSDimitry Andric Lock lock(&mu_for_globals); 11668d75effSDimitry Andric int res = 0; 11768d75effSDimitry Andric for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { 11868d75effSDimitry Andric const Global &g = *l->g; 11968d75effSDimitry Andric if (flags()->report_globals >= 2) 12068d75effSDimitry Andric ReportGlobal(g, "Search"); 12168d75effSDimitry Andric if (IsAddressNearGlobal(addr, g)) { 12268d75effSDimitry Andric internal_memcpy(&globals[res], &g, sizeof(g)); 12368d75effSDimitry Andric if (reg_sites) 12468d75effSDimitry Andric reg_sites[res] = FindRegistrationSite(&g); 12568d75effSDimitry Andric res++; 12668d75effSDimitry Andric if (res == max_globals) 12768d75effSDimitry Andric break; 12868d75effSDimitry Andric } 12968d75effSDimitry Andric } 13068d75effSDimitry Andric return res; 13168d75effSDimitry Andric } 13268d75effSDimitry Andric 13368d75effSDimitry Andric enum GlobalSymbolState { 13468d75effSDimitry Andric UNREGISTERED = 0, 13568d75effSDimitry Andric REGISTERED = 1 13668d75effSDimitry Andric }; 13768d75effSDimitry Andric 13868d75effSDimitry Andric // Check ODR violation for given global G via special ODR indicator. We use 13968d75effSDimitry Andric // this method in case compiler instruments global variables through their 14068d75effSDimitry Andric // local aliases. 14168d75effSDimitry Andric static void CheckODRViolationViaIndicator(const Global *g) { 14268d75effSDimitry Andric // Instrumentation requests to skip ODR check. 14368d75effSDimitry Andric if (g->odr_indicator == UINTPTR_MAX) 14468d75effSDimitry Andric return; 14568d75effSDimitry Andric u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator); 14668d75effSDimitry Andric if (*odr_indicator == UNREGISTERED) { 14768d75effSDimitry Andric *odr_indicator = REGISTERED; 14868d75effSDimitry Andric return; 14968d75effSDimitry Andric } 15068d75effSDimitry Andric // If *odr_indicator is DEFINED, some module have already registered 15168d75effSDimitry Andric // externally visible symbol with the same name. This is an ODR violation. 15268d75effSDimitry Andric for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { 15368d75effSDimitry Andric if (g->odr_indicator == l->g->odr_indicator && 15468d75effSDimitry Andric (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && 15568d75effSDimitry Andric !IsODRViolationSuppressed(g->name)) 15668d75effSDimitry Andric ReportODRViolation(g, FindRegistrationSite(g), 15768d75effSDimitry Andric l->g, FindRegistrationSite(l->g)); 15868d75effSDimitry Andric } 15968d75effSDimitry Andric } 16068d75effSDimitry Andric 16168d75effSDimitry Andric // Check ODR violation for given global G by checking if it's already poisoned. 16268d75effSDimitry Andric // We use this method in case compiler doesn't use private aliases for global 16368d75effSDimitry Andric // variables. 16468d75effSDimitry Andric static void CheckODRViolationViaPoisoning(const Global *g) { 16568d75effSDimitry Andric if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { 16668d75effSDimitry Andric // This check may not be enough: if the first global is much larger 16768d75effSDimitry Andric // the entire redzone of the second global may be within the first global. 16868d75effSDimitry Andric for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { 16968d75effSDimitry Andric if (g->beg == l->g->beg && 17068d75effSDimitry Andric (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && 17168d75effSDimitry Andric !IsODRViolationSuppressed(g->name)) 17268d75effSDimitry Andric ReportODRViolation(g, FindRegistrationSite(g), 17368d75effSDimitry Andric l->g, FindRegistrationSite(l->g)); 17468d75effSDimitry Andric } 17568d75effSDimitry Andric } 17668d75effSDimitry Andric } 17768d75effSDimitry Andric 17868d75effSDimitry Andric // Clang provides two different ways for global variables protection: 17968d75effSDimitry Andric // it can poison the global itself or its private alias. In former 18068d75effSDimitry Andric // case we may poison same symbol multiple times, that can help us to 18168d75effSDimitry Andric // cheaply detect ODR violation: if we try to poison an already poisoned 18268d75effSDimitry Andric // global, we have ODR violation error. 18368d75effSDimitry Andric // In latter case, we poison each symbol exactly once, so we use special 18468d75effSDimitry Andric // indicator symbol to perform similar check. 18568d75effSDimitry Andric // In either case, compiler provides a special odr_indicator field to Global 18668d75effSDimitry Andric // structure, that can contain two kinds of values: 18768d75effSDimitry Andric // 1) Non-zero value. In this case, odr_indicator is an address of 18868d75effSDimitry Andric // corresponding indicator variable for given global. 18968d75effSDimitry Andric // 2) Zero. This means that we don't use private aliases for global variables 19068d75effSDimitry Andric // and can freely check ODR violation with the first method. 19168d75effSDimitry Andric // 19268d75effSDimitry Andric // This routine chooses between two different methods of ODR violation 19368d75effSDimitry Andric // detection. 19468d75effSDimitry Andric static inline bool UseODRIndicator(const Global *g) { 19568d75effSDimitry Andric return g->odr_indicator > 0; 19668d75effSDimitry Andric } 19768d75effSDimitry Andric 19868d75effSDimitry Andric // Register a global variable. 19968d75effSDimitry Andric // This function may be called more than once for every global 20068d75effSDimitry Andric // so we store the globals in a map. 20168d75effSDimitry Andric static void RegisterGlobal(const Global *g) { 2025f757f3fSDimitry Andric CHECK(AsanInited()); 20368d75effSDimitry Andric if (flags()->report_globals >= 2) 20468d75effSDimitry Andric ReportGlobal(*g, "Added"); 20568d75effSDimitry Andric CHECK(flags()->report_globals); 20668d75effSDimitry Andric CHECK(AddrIsInMem(g->beg)); 20768d75effSDimitry Andric if (!AddrIsAlignedByGranularity(g->beg)) { 20868d75effSDimitry Andric Report("The following global variable is not properly aligned.\n"); 20968d75effSDimitry Andric Report("This may happen if another global with the same name\n"); 21068d75effSDimitry Andric Report("resides in another non-instrumented module.\n"); 21168d75effSDimitry Andric Report("Or the global comes from a C file built w/o -fno-common.\n"); 21268d75effSDimitry Andric Report("In either case this is likely an ODR violation bug,\n"); 21368d75effSDimitry Andric Report("but AddressSanitizer can not provide more details.\n"); 21468d75effSDimitry Andric ReportODRViolation(g, FindRegistrationSite(g), g, FindRegistrationSite(g)); 21568d75effSDimitry Andric CHECK(AddrIsAlignedByGranularity(g->beg)); 21668d75effSDimitry Andric } 21768d75effSDimitry Andric CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); 21868d75effSDimitry Andric if (flags()->detect_odr_violation) { 21968d75effSDimitry Andric // Try detecting ODR (One Definition Rule) violation, i.e. the situation 22068d75effSDimitry Andric // where two globals with the same name are defined in different modules. 22168d75effSDimitry Andric if (UseODRIndicator(g)) 22268d75effSDimitry Andric CheckODRViolationViaIndicator(g); 22368d75effSDimitry Andric else 22468d75effSDimitry Andric CheckODRViolationViaPoisoning(g); 22568d75effSDimitry Andric } 22668d75effSDimitry Andric if (CanPoisonMemory()) 22768d75effSDimitry Andric PoisonRedZones(*g); 2285f757f3fSDimitry Andric ListOfGlobals *l = new (GetGlobalLowLevelAllocator()) ListOfGlobals; 22968d75effSDimitry Andric l->g = g; 23068d75effSDimitry Andric l->next = list_of_all_globals; 23168d75effSDimitry Andric list_of_all_globals = l; 23268d75effSDimitry Andric if (g->has_dynamic_init) { 23368d75effSDimitry Andric if (!dynamic_init_globals) { 2345f757f3fSDimitry Andric dynamic_init_globals = new (GetGlobalLowLevelAllocator()) VectorOfGlobals; 23568d75effSDimitry Andric dynamic_init_globals->reserve(kDynamicInitGlobalsInitialCapacity); 23668d75effSDimitry Andric } 23768d75effSDimitry Andric DynInitGlobal dyn_global = { *g, false }; 23868d75effSDimitry Andric dynamic_init_globals->push_back(dyn_global); 23968d75effSDimitry Andric } 24068d75effSDimitry Andric } 24168d75effSDimitry Andric 24268d75effSDimitry Andric static void UnregisterGlobal(const Global *g) { 2435f757f3fSDimitry Andric CHECK(AsanInited()); 24468d75effSDimitry Andric if (flags()->report_globals >= 2) 24568d75effSDimitry Andric ReportGlobal(*g, "Removed"); 24668d75effSDimitry Andric CHECK(flags()->report_globals); 24768d75effSDimitry Andric CHECK(AddrIsInMem(g->beg)); 24868d75effSDimitry Andric CHECK(AddrIsAlignedByGranularity(g->beg)); 24968d75effSDimitry Andric CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); 25068d75effSDimitry Andric if (CanPoisonMemory()) 25168d75effSDimitry Andric PoisonShadowForGlobal(g, 0); 25268d75effSDimitry Andric // We unpoison the shadow memory for the global but we do not remove it from 25368d75effSDimitry Andric // the list because that would require O(n^2) time with the current list 25468d75effSDimitry Andric // implementation. It might not be worth doing anyway. 25568d75effSDimitry Andric 25668d75effSDimitry Andric // Release ODR indicator. 25768d75effSDimitry Andric if (UseODRIndicator(g) && g->odr_indicator != UINTPTR_MAX) { 25868d75effSDimitry Andric u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator); 25968d75effSDimitry Andric *odr_indicator = UNREGISTERED; 26068d75effSDimitry Andric } 26168d75effSDimitry Andric } 26268d75effSDimitry Andric 26368d75effSDimitry Andric void StopInitOrderChecking() { 264349cc55cSDimitry Andric Lock lock(&mu_for_globals); 26568d75effSDimitry Andric if (!flags()->check_initialization_order || !dynamic_init_globals) 26668d75effSDimitry Andric return; 26768d75effSDimitry Andric flags()->check_initialization_order = false; 26868d75effSDimitry Andric for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { 26968d75effSDimitry Andric DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; 27068d75effSDimitry Andric const Global *g = &dyn_g.g; 27168d75effSDimitry Andric // Unpoison the whole global. 27268d75effSDimitry Andric PoisonShadowForGlobal(g, 0); 27368d75effSDimitry Andric // Poison redzones back. 27468d75effSDimitry Andric PoisonRedZones(*g); 27568d75effSDimitry Andric } 27668d75effSDimitry Andric } 27768d75effSDimitry Andric 27868d75effSDimitry Andric static bool IsASCII(unsigned char c) { return /*0x00 <= c &&*/ c <= 0x7F; } 27968d75effSDimitry Andric 28068d75effSDimitry Andric const char *MaybeDemangleGlobalName(const char *name) { 28168d75effSDimitry Andric // We can spoil names of globals with C linkage, so use an heuristic 28268d75effSDimitry Andric // approach to check if the name should be demangled. 28368d75effSDimitry Andric bool should_demangle = false; 28468d75effSDimitry Andric if (name[0] == '_' && name[1] == 'Z') 28568d75effSDimitry Andric should_demangle = true; 28668d75effSDimitry Andric else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?') 28768d75effSDimitry Andric should_demangle = true; 28868d75effSDimitry Andric 28968d75effSDimitry Andric return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name; 29068d75effSDimitry Andric } 29168d75effSDimitry Andric 29268d75effSDimitry Andric // Check if the global is a zero-terminated ASCII string. If so, print it. 29368d75effSDimitry Andric void PrintGlobalNameIfASCII(InternalScopedString *str, const __asan_global &g) { 29468d75effSDimitry Andric for (uptr p = g.beg; p < g.beg + g.size - 1; p++) { 29568d75effSDimitry Andric unsigned char c = *(unsigned char *)p; 29668d75effSDimitry Andric if (c == '\0' || !IsASCII(c)) return; 29768d75effSDimitry Andric } 29868d75effSDimitry Andric if (*(char *)(g.beg + g.size - 1) != '\0') return; 2995f757f3fSDimitry Andric str->AppendF(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name), 30068d75effSDimitry Andric (char *)g.beg); 30168d75effSDimitry Andric } 30268d75effSDimitry Andric 3035f757f3fSDimitry Andric void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g, 3045f757f3fSDimitry Andric bool print_module_name) { 30581ad6265SDimitry Andric DataInfo info; 3065f757f3fSDimitry Andric if (Symbolizer::GetOrInit()->SymbolizeData(g.beg, &info) && info.line != 0) { 3075f757f3fSDimitry Andric str->AppendF("%s:%d", info.file, static_cast<int>(info.line)); 30806c3fb27SDimitry Andric } else if (g.gcc_location != 0) { 30906c3fb27SDimitry Andric // Fallback to Global::gcc_location 3105f757f3fSDimitry Andric str->AppendF("%s", g.gcc_location->filename ? g.gcc_location->filename 3115f757f3fSDimitry Andric : g.module_name); 3125f757f3fSDimitry Andric if (g.gcc_location->line_no) 3135f757f3fSDimitry Andric str->AppendF(":%d", g.gcc_location->line_no); 3145f757f3fSDimitry Andric if (g.gcc_location->column_no) 3155f757f3fSDimitry Andric str->AppendF(":%d", g.gcc_location->column_no); 31681ad6265SDimitry Andric } else { 3175f757f3fSDimitry Andric str->AppendF("%s", g.module_name); 31881ad6265SDimitry Andric } 3195f757f3fSDimitry Andric if (print_module_name && info.module) 3205f757f3fSDimitry Andric str->AppendF(" in %s", info.module); 32168d75effSDimitry Andric } 32268d75effSDimitry Andric 32368d75effSDimitry Andric } // namespace __asan 32468d75effSDimitry Andric 32568d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1 32668d75effSDimitry Andric using namespace __asan; 32768d75effSDimitry Andric 32868d75effSDimitry Andric // Apply __asan_register_globals to all globals found in the same loaded 32968d75effSDimitry Andric // executable or shared library as `flag'. The flag tracks whether globals have 33068d75effSDimitry Andric // already been registered or not for this image. 33168d75effSDimitry Andric void __asan_register_image_globals(uptr *flag) { 33268d75effSDimitry Andric if (*flag) 33368d75effSDimitry Andric return; 33468d75effSDimitry Andric AsanApplyToGlobals(__asan_register_globals, flag); 33568d75effSDimitry Andric *flag = 1; 33668d75effSDimitry Andric } 33768d75effSDimitry Andric 33868d75effSDimitry Andric // This mirrors __asan_register_image_globals. 33968d75effSDimitry Andric void __asan_unregister_image_globals(uptr *flag) { 34068d75effSDimitry Andric if (!*flag) 34168d75effSDimitry Andric return; 34268d75effSDimitry Andric AsanApplyToGlobals(__asan_unregister_globals, flag); 34368d75effSDimitry Andric *flag = 0; 34468d75effSDimitry Andric } 34568d75effSDimitry Andric 34668d75effSDimitry Andric void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { 347*0fca6ea1SDimitry Andric if (*flag || start == stop) 348*0fca6ea1SDimitry Andric return; 34968d75effSDimitry Andric CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); 35068d75effSDimitry Andric __asan_global *globals_start = (__asan_global*)start; 35168d75effSDimitry Andric __asan_global *globals_stop = (__asan_global*)stop; 35268d75effSDimitry Andric __asan_register_globals(globals_start, globals_stop - globals_start); 35368d75effSDimitry Andric *flag = 1; 35468d75effSDimitry Andric } 35568d75effSDimitry Andric 35668d75effSDimitry Andric void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) { 357*0fca6ea1SDimitry Andric if (!*flag || start == stop) 358*0fca6ea1SDimitry Andric return; 35968d75effSDimitry Andric CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); 36068d75effSDimitry Andric __asan_global *globals_start = (__asan_global*)start; 36168d75effSDimitry Andric __asan_global *globals_stop = (__asan_global*)stop; 36268d75effSDimitry Andric __asan_unregister_globals(globals_start, globals_stop - globals_start); 36368d75effSDimitry Andric *flag = 0; 36468d75effSDimitry Andric } 36568d75effSDimitry Andric 36668d75effSDimitry Andric // Register an array of globals. 36768d75effSDimitry Andric void __asan_register_globals(__asan_global *globals, uptr n) { 36868d75effSDimitry Andric if (!flags()->report_globals) return; 36968d75effSDimitry Andric GET_STACK_TRACE_MALLOC; 37068d75effSDimitry Andric u32 stack_id = StackDepotPut(stack); 371349cc55cSDimitry Andric Lock lock(&mu_for_globals); 37268d75effSDimitry Andric if (!global_registration_site_vector) { 37368d75effSDimitry Andric global_registration_site_vector = 3745f757f3fSDimitry Andric new (GetGlobalLowLevelAllocator()) GlobalRegistrationSiteVector; 37568d75effSDimitry Andric global_registration_site_vector->reserve(128); 37668d75effSDimitry Andric } 37768d75effSDimitry Andric GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]}; 37868d75effSDimitry Andric global_registration_site_vector->push_back(site); 37968d75effSDimitry Andric if (flags()->report_globals >= 2) { 38068d75effSDimitry Andric PRINT_CURRENT_STACK(); 381349cc55cSDimitry Andric Printf("=== ID %d; %p %p\n", stack_id, (void *)&globals[0], 382349cc55cSDimitry Andric (void *)&globals[n - 1]); 38368d75effSDimitry Andric } 38468d75effSDimitry Andric for (uptr i = 0; i < n; i++) { 38568d75effSDimitry Andric if (SANITIZER_WINDOWS && globals[i].beg == 0) { 38668d75effSDimitry Andric // The MSVC incremental linker may pad globals out to 256 bytes. As long 38768d75effSDimitry Andric // as __asan_global is less than 256 bytes large and its size is a power 38868d75effSDimitry Andric // of two, we can skip over the padding. 38968d75effSDimitry Andric static_assert( 39068d75effSDimitry Andric sizeof(__asan_global) < 256 && 39168d75effSDimitry Andric (sizeof(__asan_global) & (sizeof(__asan_global) - 1)) == 0, 39268d75effSDimitry Andric "sizeof(__asan_global) incompatible with incremental linker padding"); 39368d75effSDimitry Andric // If these are padding bytes, the rest of the global should be zero. 39468d75effSDimitry Andric CHECK(globals[i].size == 0 && globals[i].size_with_redzone == 0 && 39568d75effSDimitry Andric globals[i].name == nullptr && globals[i].module_name == nullptr && 39668d75effSDimitry Andric globals[i].odr_indicator == 0); 39768d75effSDimitry Andric continue; 39868d75effSDimitry Andric } 39968d75effSDimitry Andric RegisterGlobal(&globals[i]); 40068d75effSDimitry Andric } 40168d75effSDimitry Andric 40268d75effSDimitry Andric // Poison the metadata. It should not be accessible to user code. 40368d75effSDimitry Andric PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global), 40468d75effSDimitry Andric kAsanGlobalRedzoneMagic); 40568d75effSDimitry Andric } 40668d75effSDimitry Andric 40768d75effSDimitry Andric // Unregister an array of globals. 40868d75effSDimitry Andric // We must do this when a shared objects gets dlclosed. 40968d75effSDimitry Andric void __asan_unregister_globals(__asan_global *globals, uptr n) { 41068d75effSDimitry Andric if (!flags()->report_globals) return; 411349cc55cSDimitry Andric Lock lock(&mu_for_globals); 41268d75effSDimitry Andric for (uptr i = 0; i < n; i++) { 41368d75effSDimitry Andric if (SANITIZER_WINDOWS && globals[i].beg == 0) { 41468d75effSDimitry Andric // Skip globals that look like padding from the MSVC incremental linker. 41568d75effSDimitry Andric // See comment in __asan_register_globals. 41668d75effSDimitry Andric continue; 41768d75effSDimitry Andric } 41868d75effSDimitry Andric UnregisterGlobal(&globals[i]); 41968d75effSDimitry Andric } 42068d75effSDimitry Andric 42168d75effSDimitry Andric // Unpoison the metadata. 42268d75effSDimitry Andric PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global), 0); 42368d75effSDimitry Andric } 42468d75effSDimitry Andric 42568d75effSDimitry Andric // This method runs immediately prior to dynamic initialization in each TU, 42668d75effSDimitry Andric // when all dynamically initialized globals are unpoisoned. This method 42768d75effSDimitry Andric // poisons all global variables not defined in this TU, so that a dynamic 42868d75effSDimitry Andric // initializer can only touch global variables in the same TU. 42968d75effSDimitry Andric void __asan_before_dynamic_init(const char *module_name) { 43068d75effSDimitry Andric if (!flags()->check_initialization_order || 43168d75effSDimitry Andric !CanPoisonMemory() || 43268d75effSDimitry Andric !dynamic_init_globals) 43368d75effSDimitry Andric return; 43468d75effSDimitry Andric bool strict_init_order = flags()->strict_init_order; 43568d75effSDimitry Andric CHECK(module_name); 4365f757f3fSDimitry Andric CHECK(AsanInited()); 437349cc55cSDimitry Andric Lock lock(&mu_for_globals); 43868d75effSDimitry Andric if (flags()->report_globals >= 3) 43968d75effSDimitry Andric Printf("DynInitPoison module: %s\n", module_name); 44068d75effSDimitry Andric for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { 44168d75effSDimitry Andric DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; 44268d75effSDimitry Andric const Global *g = &dyn_g.g; 44368d75effSDimitry Andric if (dyn_g.initialized) 44468d75effSDimitry Andric continue; 44568d75effSDimitry Andric if (g->module_name != module_name) 44668d75effSDimitry Andric PoisonShadowForGlobal(g, kAsanInitializationOrderMagic); 44768d75effSDimitry Andric else if (!strict_init_order) 44868d75effSDimitry Andric dyn_g.initialized = true; 44968d75effSDimitry Andric } 45068d75effSDimitry Andric } 45168d75effSDimitry Andric 45268d75effSDimitry Andric // This method runs immediately after dynamic initialization in each TU, when 45368d75effSDimitry Andric // all dynamically initialized globals except for those defined in the current 45468d75effSDimitry Andric // TU are poisoned. It simply unpoisons all dynamically initialized globals. 45568d75effSDimitry Andric void __asan_after_dynamic_init() { 45668d75effSDimitry Andric if (!flags()->check_initialization_order || 45768d75effSDimitry Andric !CanPoisonMemory() || 45868d75effSDimitry Andric !dynamic_init_globals) 45968d75effSDimitry Andric return; 4605f757f3fSDimitry Andric CHECK(AsanInited()); 461349cc55cSDimitry Andric Lock lock(&mu_for_globals); 46268d75effSDimitry Andric // FIXME: Optionally report that we're unpoisoning globals from a module. 46368d75effSDimitry Andric for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { 46468d75effSDimitry Andric DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; 46568d75effSDimitry Andric const Global *g = &dyn_g.g; 46668d75effSDimitry Andric if (!dyn_g.initialized) { 46768d75effSDimitry Andric // Unpoison the whole global. 46868d75effSDimitry Andric PoisonShadowForGlobal(g, 0); 46968d75effSDimitry Andric // Poison redzones back. 47068d75effSDimitry Andric PoisonRedZones(*g); 47168d75effSDimitry Andric } 47268d75effSDimitry Andric } 47368d75effSDimitry Andric } 474