diff options
Diffstat (limited to 'contrib/compiler-rt/lib/asan')
30 files changed, 598 insertions, 541 deletions
diff --git a/contrib/compiler-rt/lib/asan/asan_allocator.cc b/contrib/compiler-rt/lib/asan/asan_allocator.cc index fd63ac6..2df9a51 100644 --- a/contrib/compiler-rt/lib/asan/asan_allocator.cc +++ b/contrib/compiler-rt/lib/asan/asan_allocator.cc @@ -223,7 +223,7 @@ void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) { struct Allocator { static const uptr kMaxAllowedMallocSize = - FIRST_32_SECOND_64(3UL << 30, 64UL << 30); + FIRST_32_SECOND_64(3UL << 30, 1UL << 40); static const uptr kMaxThreadLocalQuarantine = FIRST_32_SECOND_64(1 << 18, 1 << 20); @@ -354,7 +354,7 @@ struct Allocator { } CHECK(IsAligned(needed_size, min_alignment)); if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) { - Report("WARNING: AddressSanitizer failed to allocate %p bytes\n", + Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", (void*)size); return allocator.ReturnNullOrDie(); } @@ -437,11 +437,10 @@ struct Allocator { thread_stats.mallocs++; thread_stats.malloced += size; thread_stats.malloced_redzones += needed_size - size; - uptr class_id = - Min(kNumberOfSizeClasses, SizeClassMap::ClassID(needed_size)); - thread_stats.malloced_by_size[class_id]++; if (needed_size > SizeClassMap::kMaxSize) thread_stats.malloc_large++; + else + thread_stats.malloced_by_size[SizeClassMap::ClassID(needed_size)]++; void *res = reinterpret_cast<void *>(user_beg); if (can_fill && fl.max_malloc_fill_size) { diff --git a/contrib/compiler-rt/lib/asan/asan_allocator.h b/contrib/compiler-rt/lib/asan/asan_allocator.h index 3208d1f..5ccd00c 100644 --- a/contrib/compiler-rt/lib/asan/asan_allocator.h +++ b/contrib/compiler-rt/lib/asan/asan_allocator.h @@ -29,7 +29,6 @@ enum AllocType { FROM_NEW_BR = 3 // Memory block came from operator new [ ] }; -static const uptr kNumberOfSizeClasses = 255; struct AsanChunk; struct AllocatorOptions { @@ -137,6 +136,7 @@ typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16, AsanMapUnmapCallback> PrimaryAllocator; #endif // SANITIZER_CAN_USE_ALLOCATOR64 +static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses; typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache; typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator; typedef CombinedAllocator<PrimaryAllocator, AllocatorCache, diff --git a/contrib/compiler-rt/lib/asan/asan_fake_stack.cc b/contrib/compiler-rt/lib/asan/asan_fake_stack.cc index bf4f1eb..d206411 100644 --- a/contrib/compiler-rt/lib/asan/asan_fake_stack.cc +++ b/contrib/compiler-rt/lib/asan/asan_fake_stack.cc @@ -22,6 +22,9 @@ static const u64 kMagic2 = (kMagic1 << 8) | kMagic1; static const u64 kMagic4 = (kMagic2 << 16) | kMagic2; static const u64 kMagic8 = (kMagic4 << 32) | kMagic4; +static const u64 kAllocaRedzoneSize = 32UL; +static const u64 kAllocaRedzoneMask = 31UL; + // For small size classes inline PoisonShadow for better performance. ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) { CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3. @@ -253,4 +256,24 @@ void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, if (end) *end = reinterpret_cast<void*>(frame_end); return reinterpret_cast<void*>(frame->real_stack); } + +SANITIZER_INTERFACE_ATTRIBUTE +void __asan_alloca_poison(uptr addr, uptr size) { + uptr LeftRedzoneAddr = addr - kAllocaRedzoneSize; + uptr PartialRzAddr = addr + size; + uptr RightRzAddr = (PartialRzAddr + kAllocaRedzoneMask) & ~kAllocaRedzoneMask; + uptr PartialRzAligned = PartialRzAddr & ~(SHADOW_GRANULARITY - 1); + FastPoisonShadow(LeftRedzoneAddr, kAllocaRedzoneSize, kAsanAllocaLeftMagic); + FastPoisonShadowPartialRightRedzone( + PartialRzAligned, PartialRzAddr % SHADOW_GRANULARITY, + RightRzAddr - PartialRzAligned, kAsanAllocaRightMagic); + FastPoisonShadow(RightRzAddr, kAllocaRedzoneSize, kAsanAllocaRightMagic); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __asan_allocas_unpoison(uptr top, uptr bottom) { + if ((!top) || (top > bottom)) return; + REAL(memset)(reinterpret_cast<void*>(MemToShadow(top)), 0, + (bottom - top) / SHADOW_GRANULARITY); +} } // extern "C" diff --git a/contrib/compiler-rt/lib/asan/asan_flags.cc b/contrib/compiler-rt/lib/asan/asan_flags.cc index efb7767..e8ea549 100644 --- a/contrib/compiler-rt/lib/asan/asan_flags.cc +++ b/contrib/compiler-rt/lib/asan/asan_flags.cc @@ -20,6 +20,8 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" +#include "ubsan/ubsan_flags.h" +#include "ubsan/ubsan_platform.h" namespace __asan { @@ -72,8 +74,8 @@ void InitializeFlags() { RegisterAsanFlags(&asan_parser, f); RegisterCommonFlags(&asan_parser); - // Set the default values and prepare for parsing LSan flags (which can also - // overwrite common flags). + // Set the default values and prepare for parsing LSan and UBSan flags + // (which can also overwrite common flags). #if CAN_SANITIZE_LEAKS __lsan::Flags *lf = __lsan::flags(); lf->SetDefaults(); @@ -83,6 +85,15 @@ void InitializeFlags() { RegisterCommonFlags(&lsan_parser); #endif +#if CAN_SANITIZE_UB + __ubsan::Flags *uf = __ubsan::flags(); + uf->SetDefaults(); + + FlagParser ubsan_parser; + __ubsan::RegisterUbsanFlags(&ubsan_parser, uf); + RegisterCommonFlags(&ubsan_parser); +#endif + // Override from ASan compile definition. const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); asan_parser.ParseString(asan_compile_def); @@ -90,12 +101,19 @@ void InitializeFlags() { // Override from user-specified string. const char *asan_default_options = MaybeCallAsanDefaultOptions(); asan_parser.ParseString(asan_default_options); +#if CAN_SANITIZE_UB + const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); + ubsan_parser.ParseString(ubsan_default_options); +#endif // Override from command line. asan_parser.ParseString(GetEnv("ASAN_OPTIONS")); #if CAN_SANITIZE_LEAKS lsan_parser.ParseString(GetEnv("LSAN_OPTIONS")); #endif +#if CAN_SANITIZE_UB + ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS")); +#endif // Let activation flags override current settings. On Android they come // from a system property. On other platforms this is no-op. diff --git a/contrib/compiler-rt/lib/asan/asan_globals.cc b/contrib/compiler-rt/lib/asan/asan_globals.cc index 06140bb..c34b1d3 100644 --- a/contrib/compiler-rt/lib/asan/asan_globals.cc +++ b/contrib/compiler-rt/lib/asan/asan_globals.cc @@ -18,6 +18,7 @@ #include "asan_report.h" #include "asan_stack.h" #include "asan_stats.h" +#include "asan_suppressions.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_mutex.h" @@ -73,7 +74,7 @@ ALWAYS_INLINE void PoisonRedZones(const Global &g) { const uptr kMinimalDistanceFromAnotherGlobal = 64; -bool IsAddressNearGlobal(uptr addr, const __asan_global &g) { +static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) { if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false; if (addr >= g.beg + g.size_with_redzone) return false; return true; @@ -90,36 +91,40 @@ static void ReportGlobal(const Global &g, const char *prefix) { } } -static bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print, - Global *output_global) { - if (!flags()->report_globals) return false; +static u32 FindRegistrationSite(const Global *g) { + mu_for_globals.CheckLocked(); + CHECK(global_registration_site_vector); + for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) { + GlobalRegistrationSite &grs = (*global_registration_site_vector)[i]; + if (g >= grs.g_first && g <= grs.g_last) + return grs.stack_id; + } + return 0; +} + +int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites, + int max_globals) { + if (!flags()->report_globals) return 0; BlockingMutexLock lock(&mu_for_globals); - bool res = false; + int res = 0; for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { const Global &g = *l->g; - if (print) { - if (flags()->report_globals >= 2) - ReportGlobal(g, "Search"); - res |= DescribeAddressRelativeToGlobal(addr, size, g); - } else { - if (IsAddressNearGlobal(addr, g)) { - CHECK(output_global); - *output_global = g; - return true; - } + if (flags()->report_globals >= 2) + ReportGlobal(g, "Search"); + if (IsAddressNearGlobal(addr, g)) { + globals[res] = g; + if (reg_sites) + reg_sites[res] = FindRegistrationSite(&g); + res++; + if (res == max_globals) break; } } return res; } -bool DescribeAddressIfGlobal(uptr addr, uptr size) { - return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true, - /* output_global */ nullptr); -} - bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) { Global g = {}; - if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) { + if (GetGlobalsForAddress(addr, &g, nullptr, 1)) { internal_strncpy(descr->name, g.name, descr->name_size); descr->region_address = g.beg; descr->region_size = g.size; @@ -129,16 +134,6 @@ bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) { return false; } -u32 FindRegistrationSite(const Global *g) { - CHECK(global_registration_site_vector); - for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) { - GlobalRegistrationSite &grs = (*global_registration_site_vector)[i]; - if (g >= grs.g_first && g <= grs.g_last) - return grs.stack_id; - } - return 0; -} - // Register a global variable. // This function may be called more than once for every global // so we store the globals in a map. @@ -158,7 +153,8 @@ static void RegisterGlobal(const Global *g) { // the entire redzone of the second global may be within the first global. for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { if (g->beg == l->g->beg && - (flags()->detect_odr_violation >= 2 || g->size != l->g->size)) + (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && + !IsODRViolationSuppressed(g->name)) ReportODRViolation(g, FindRegistrationSite(g), l->g, FindRegistrationSite(l->g)); } @@ -210,20 +206,6 @@ void StopInitOrderChecking() { } } -#if SANITIZER_WINDOWS // Should only be called on Windows. -SANITIZER_INTERFACE_ATTRIBUTE -void UnregisterGlobalsInRange(void *beg, void *end) { - if (!flags()->report_globals) - return; - BlockingMutexLock lock(&mu_for_globals); - for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { - void *address = (void *)l->g->beg; - if (beg <= address && address < end) - UnregisterGlobal(l->g); - } -} -#endif - } // namespace __asan // ---------------------- Interface ---------------- {{{1 @@ -232,7 +214,7 @@ using namespace __asan; // NOLINT // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; - GET_STACK_TRACE_FATAL_HERE; + GET_STACK_TRACE_MALLOC; u32 stack_id = StackDepotPut(stack); BlockingMutexLock lock(&mu_for_globals); if (!global_registration_site_vector) diff --git a/contrib/compiler-rt/lib/asan/asan_interceptors.cc b/contrib/compiler-rt/lib/asan/asan_interceptors.cc index 3dc7ec6..d8b48d3 100644 --- a/contrib/compiler-rt/lib/asan/asan_interceptors.cc +++ b/contrib/compiler-rt/lib/asan/asan_interceptors.cc @@ -23,6 +23,10 @@ #include "asan_suppressions.h" #include "sanitizer_common/sanitizer_libc.h" +#if SANITIZER_POSIX +#include "sanitizer_common/sanitizer_posix.h" +#endif + namespace __asan { // Return true if we can quickly decide that the region is unpoisoned. @@ -65,7 +69,7 @@ struct AsanInterceptorContext { } \ if (!suppressed) { \ GET_CURRENT_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, __bad, isWrite, __size); \ + __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0); \ } \ } \ } while (0) @@ -75,6 +79,13 @@ struct AsanInterceptorContext { #define ASAN_WRITE_RANGE(ctx, offset, size) \ ACCESS_MEMORY_RANGE(ctx, offset, size, true) +#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \ + ASAN_READ_RANGE((ctx), (s), \ + common_flags()->strict_string_checks ? (len) + 1 : (n)) + +#define ASAN_READ_STRING(ctx, s, n) \ + ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n)) + // Behavior of functions like "memcpy" or "strcpy" is undefined // if memory intervals overlap. We report error in this case. // Macro is used to avoid creation of new frames. @@ -120,17 +131,6 @@ using namespace __asan; // NOLINT DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) -#if !SANITIZER_MAC -#define ASAN_INTERCEPT_FUNC(name) \ - do { \ - if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \ - VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \ - } while (0) -#else -// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. -#define ASAN_INTERCEPT_FUNC(name) -#endif // SANITIZER_MAC - #define ASAN_INTERCEPTOR_ENTER(ctx, func) \ AsanInterceptorContext _ctx = {#func}; \ ctx = (void *)&_ctx; \ @@ -171,11 +171,24 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) do { \ } while (false) #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) +// Strict init-order checking is dlopen-hostile: +// https://code.google.com/p/address-sanitizer/issues/detail?id=178 +#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ + if (flags()->strict_init_order) { \ + StopInitOrderChecking(); \ + } #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ CoverageUpdateMapping() #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping() #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited) +#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ + if (AsanThread *t = GetCurrentThread()) { \ + *begin = t->tls_begin(); \ + *end = t->tls_end(); \ + } else { \ + *begin = *end = 0; \ + } #include "sanitizer_common/sanitizer_common_interceptors.inc" // Syscall interceptors don't have contexts, we don't support suppressions @@ -200,12 +213,6 @@ struct ThreadStartParam { }; static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { -#if SANITIZER_WINDOWS - // FIXME: this is a bandaid fix for PR22025. - AsanThread *t = (AsanThread*)arg; - SetCurrentThread(t); - return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr); -#else ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg); AsanThread *t = nullptr; while ((t = reinterpret_cast<AsanThread *>( @@ -213,7 +220,6 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { internal_sched_yield(); SetCurrentThread(t); return t->ThreadStart(GetTid(), ¶m->is_registered); -#endif } #if ASAN_INTERCEPT_PTHREAD_CREATE @@ -302,7 +308,7 @@ static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) { ssize += stack - bottom; ssize = RoundUpTo(ssize, PageSize); static const uptr kMaxSaneContextStackSize = 1 << 22; // 4 Mb - if (ssize && ssize <= kMaxSaneContextStackSize) { + if (AddrIsInMem(bottom) && ssize && ssize <= kMaxSaneContextStackSize) { PoisonShadow(bottom, ssize, 0); } } @@ -357,30 +363,6 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { } #endif -#if SANITIZER_WINDOWS -INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { - CHECK(REAL(RaiseException)); - __asan_handle_no_return(); - REAL(RaiseException)(a, b, c, d); -} - -INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) { - CHECK(REAL(_except_handler3)); - __asan_handle_no_return(); - return REAL(_except_handler3)(a, b, c, d); -} - -#if ASAN_DYNAMIC -// This handler is named differently in -MT and -MD CRTs. -#define _except_handler4 _except_handler4_common -#endif -INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { - CHECK(REAL(_except_handler4)); - __asan_handle_no_return(); - return REAL(_except_handler4)(a, b, c, d); -} -#endif - static inline int CharCmp(unsigned char c1, unsigned char c2) { return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; } @@ -511,8 +493,9 @@ INTERCEPTOR(char*, strchr, const char *str, int c) { ENSURE_ASAN_INITED(); char *result = REAL(strchr)(str, c); if (flags()->replace_str) { - uptr bytes_read = (result ? result - str : REAL(strlen)(str)) + 1; - ASAN_READ_RANGE(ctx, str, bytes_read); + uptr len = REAL(strlen)(str); + uptr bytes_read = (result ? result - str : len) + 1; + ASAN_READ_STRING_OF_LEN(ctx, str, len, bytes_read); } return result; } @@ -541,7 +524,7 @@ INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT uptr from_length = REAL(strlen)(from); ASAN_READ_RANGE(ctx, from, from_length + 1); uptr to_length = REAL(strlen)(to); - ASAN_READ_RANGE(ctx, to, to_length); + ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); // If the copying actually happens, the |from| string should not overlap // with the resulting string starting at |to|, which has a length of @@ -563,7 +546,7 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { uptr copy_length = Min(size, from_length + 1); ASAN_READ_RANGE(ctx, from, copy_length); uptr to_length = REAL(strlen)(to); - ASAN_READ_RANGE(ctx, to, to_length); + ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); if (from_length > 0) { CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1, @@ -665,23 +648,6 @@ INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) { } #endif // ASAN_INTERCEPT_STRNLEN -static inline bool IsValidStrtolBase(int base) { - return (base == 0) || (2 <= base && base <= 36); -} - -static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) { - CHECK(endptr); - if (nptr == *endptr) { - // No digits were found at strtol call, we need to find out the last - // symbol accessed by strtoll on our own. - // We get this symbol by skipping leading blanks and optional +/- sign. - while (IsSpace(*nptr)) nptr++; - if (*nptr == '+' || *nptr == '-') nptr++; - *endptr = const_cast<char *>(nptr); - } - CHECK(*endptr >= nptr); -} - INTERCEPTOR(long, strtol, const char *nptr, // NOLINT char **endptr, int base) { void *ctx; @@ -692,13 +658,7 @@ INTERCEPTOR(long, strtol, const char *nptr, // NOLINT } char *real_endptr; long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT - if (endptr != 0) { - *endptr = real_endptr; - } - if (IsValidStrtolBase(base)) { - FixRealStrtolEndptr(nptr, &real_endptr); - ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1); - } + StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); return result; } @@ -719,7 +679,7 @@ INTERCEPTOR(int, atoi, const char *nptr) { // different from int). So, we just imitate this behavior. int result = REAL(strtol)(nptr, &real_endptr, 10); FixRealStrtolEndptr(nptr, &real_endptr); - ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1); + ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } @@ -736,7 +696,7 @@ INTERCEPTOR(long, atol, const char *nptr) { // NOLINT char *real_endptr; long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT FixRealStrtolEndptr(nptr, &real_endptr); - ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1); + ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } @@ -751,16 +711,7 @@ INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT } char *real_endptr; long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT - if (endptr != 0) { - *endptr = real_endptr; - } - // If base has unsupported value, strtoll can exit with EINVAL - // without reading any characters. So do additional checks only - // if base is valid. - if (IsValidStrtolBase(base)) { - FixRealStrtolEndptr(nptr, &real_endptr); - ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1); - } + StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); return result; } @@ -774,7 +725,7 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT char *real_endptr; long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT FixRealStrtolEndptr(nptr, &real_endptr); - ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1); + ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } #endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL @@ -807,36 +758,6 @@ INTERCEPTOR(int, fork, void) { } #endif // ASAN_INTERCEPT_FORK -#if SANITIZER_WINDOWS -INTERCEPTOR_WINAPI(DWORD, CreateThread, - void* security, uptr stack_size, - DWORD (__stdcall *start_routine)(void*), void* arg, - DWORD thr_flags, void* tid) { - // Strict init-order checking is thread-hostile. - if (flags()->strict_init_order) - StopInitOrderChecking(); - GET_STACK_TRACE_THREAD; - // FIXME: The CreateThread interceptor is not the same as a pthread_create - // one. This is a bandaid fix for PR22025. - bool detached = false; // FIXME: how can we determine it on Windows? - u32 current_tid = GetCurrentTidOrInvalid(); - AsanThread *t = - AsanThread::Create(start_routine, arg, current_tid, &stack, detached); - return REAL(CreateThread)(security, stack_size, - asan_thread_start, t, thr_flags, tid); -} - -namespace __asan { -void InitializeWindowsInterceptors() { - ASAN_INTERCEPT_FUNC(CreateThread); - ASAN_INTERCEPT_FUNC(RaiseException); - ASAN_INTERCEPT_FUNC(_except_handler3); - ASAN_INTERCEPT_FUNC(_except_handler4); -} - -} // namespace __asan -#endif - // ---------------------- InitializeAsanInterceptors ---------------- {{{1 namespace __asan { void InitializeAsanInterceptors() { @@ -919,10 +840,7 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(fork); #endif - // Some Windows-specific interceptors. -#if SANITIZER_WINDOWS - InitializeWindowsInterceptors(); -#endif + InitializePlatformInterceptors(); VReport(1, "AddressSanitizer: libc interceptors initialized\n"); } diff --git a/contrib/compiler-rt/lib/asan/asan_interceptors.h b/contrib/compiler-rt/lib/asan/asan_interceptors.h index ee3b82a..488ada7 100644 --- a/contrib/compiler-rt/lib/asan/asan_interceptors.h +++ b/contrib/compiler-rt/lib/asan/asan_interceptors.h @@ -92,9 +92,21 @@ struct sigaction; DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, struct sigaction *oldact) +#if !SANITIZER_MAC +#define ASAN_INTERCEPT_FUNC(name) \ + do { \ + if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \ + VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \ + } while (0) +#else +// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. +#define ASAN_INTERCEPT_FUNC(name) +#endif // SANITIZER_MAC + namespace __asan { void InitializeAsanInterceptors(); +void InitializePlatformInterceptors(); #define ENSURE_ASAN_INITED() do { \ CHECK(!asan_init_is_running); \ diff --git a/contrib/compiler-rt/lib/asan/asan_interface_internal.h b/contrib/compiler-rt/lib/asan/asan_interface_internal.h index ea7540f..ad8ebcd 100644 --- a/contrib/compiler-rt/lib/asan/asan_interface_internal.h +++ b/contrib/compiler-rt/lib/asan/asan_interface_internal.h @@ -128,7 +128,7 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_report_error(uptr pc, uptr bp, uptr sp, - uptr addr, int is_write, uptr access_size); + uptr addr, int is_write, uptr access_size, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE int __asan_set_error_exit_code(int exit_code); @@ -165,6 +165,21 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load1(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load2(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load4(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load8(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load16(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store1(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store2(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store4(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store8(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store16(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_loadN(uptr p, uptr size, + u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_storeN(uptr p, uptr size, + u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void* __asan_memcpy(void *dst, const void *src, uptr size); SANITIZER_INTERFACE_ATTRIBUTE @@ -180,6 +195,10 @@ extern "C" { void __asan_poison_intra_object_redzone(uptr p, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_unpoison_intra_object_redzone(uptr p, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_alloca_poison(uptr addr, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_allocas_unpoison(uptr top, uptr bottom); } // extern "C" #endif // ASAN_INTERFACE_INTERNAL_H diff --git a/contrib/compiler-rt/lib/asan/asan_internal.h b/contrib/compiler-rt/lib/asan/asan_internal.h index ffd3ff8..107e16e 100644 --- a/contrib/compiler-rt/lib/asan/asan_internal.h +++ b/contrib/compiler-rt/lib/asan/asan_internal.h @@ -62,21 +62,6 @@ namespace __asan { class AsanThread; using __sanitizer::StackTrace; -struct SignalContext { - void *context; - uptr addr; - uptr pc; - uptr sp; - uptr bp; - - SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) : - context(context), addr(addr), pc(pc), sp(sp), bp(bp) { - } - - // Creates signal context in a platform-specific manner. - static SignalContext Create(void *siginfo, void *context); -}; - void AsanInitFromRtl(); // asan_rtl.cc @@ -90,7 +75,6 @@ void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); -void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); void AsanOnSIGSEGV(int, void *siginfo, void *context); void DisableReexec(); @@ -109,7 +93,7 @@ void AppendToErrorMessageBuffer(const char *buffer); void *AsanDlSymNext(const char *sym); -void ReserveShadowMemoryRange(uptr beg, uptr end); +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name); // Platform-specific options. #if SANITIZER_MAC diff --git a/contrib/compiler-rt/lib/asan/asan_linux.cc b/contrib/compiler-rt/lib/asan/asan_linux.cc index 8e8bafd..9580fc7 100644 --- a/contrib/compiler-rt/lib/asan/asan_linux.cc +++ b/contrib/compiler-rt/lib/asan/asan_linux.cc @@ -68,6 +68,8 @@ asan_rt_version_t __asan_rt_version; namespace __asan { +void InitializePlatformInterceptors() {} + void DisableReexec() { // No need to re-exec on Linux. } @@ -111,6 +113,9 @@ static void ReportIncompatibleRT() { } void AsanCheckDynamicRTPrereqs() { + if (!ASAN_DYNAMIC) + return; + // Ensure that dynamic RT is the first DSO in the list const char *first_dso_name = 0; dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); @@ -152,78 +157,6 @@ void AsanCheckIncompatibleRT() { } #endif // SANITIZER_ANDROID -void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { -#if defined(__arm__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.arm_pc; - *bp = ucontext->uc_mcontext.arm_fp; - *sp = ucontext->uc_mcontext.arm_sp; -#elif defined(__aarch64__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.pc; - *bp = ucontext->uc_mcontext.regs[29]; - *sp = ucontext->uc_mcontext.sp; -#elif defined(__hppa__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.sc_iaoq[0]; - /* GCC uses %r3 whenever a frame pointer is needed. */ - *bp = ucontext->uc_mcontext.sc_gr[3]; - *sp = ucontext->uc_mcontext.sc_gr[30]; -#elif defined(__x86_64__) -# if SANITIZER_FREEBSD - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.mc_rip; - *bp = ucontext->uc_mcontext.mc_rbp; - *sp = ucontext->uc_mcontext.mc_rsp; -# else - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.gregs[REG_RIP]; - *bp = ucontext->uc_mcontext.gregs[REG_RBP]; - *sp = ucontext->uc_mcontext.gregs[REG_RSP]; -# endif -#elif defined(__i386__) -# if SANITIZER_FREEBSD - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.mc_eip; - *bp = ucontext->uc_mcontext.mc_ebp; - *sp = ucontext->uc_mcontext.mc_esp; -# else - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.gregs[REG_EIP]; - *bp = ucontext->uc_mcontext.gregs[REG_EBP]; - *sp = ucontext->uc_mcontext.gregs[REG_ESP]; -# endif -#elif defined(__powerpc__) || defined(__powerpc64__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.regs->nip; - *sp = ucontext->uc_mcontext.regs->gpr[PT_R1]; - // The powerpc{,64}-linux ABIs do not specify r31 as the frame - // pointer, but GCC always uses r31 when we need a frame pointer. - *bp = ucontext->uc_mcontext.regs->gpr[PT_R31]; -#elif defined(__sparc__) - ucontext_t *ucontext = (ucontext_t*)context; - uptr *stk_ptr; -# if defined (__arch64__) - *pc = ucontext->uc_mcontext.mc_gregs[MC_PC]; - *sp = ucontext->uc_mcontext.mc_gregs[MC_O6]; - stk_ptr = (uptr *) (*sp + 2047); - *bp = stk_ptr[15]; -# else - *pc = ucontext->uc_mcontext.gregs[REG_PC]; - *sp = ucontext->uc_mcontext.gregs[REG_O6]; - stk_ptr = (uptr *) *sp; - *bp = stk_ptr[15]; -# endif -#elif defined(__mips__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.gregs[31]; - *bp = ucontext->uc_mcontext.gregs[30]; - *sp = ucontext->uc_mcontext.gregs[29]; -#else -# error "Unsupported arch" -#endif -} - void AsanPlatformThreadInit() { // Nothing here for now. } diff --git a/contrib/compiler-rt/lib/asan/asan_mac.cc b/contrib/compiler-rt/lib/asan/asan_mac.cc index b353686..3e02837 100644 --- a/contrib/compiler-rt/lib/asan/asan_mac.cc +++ b/contrib/compiler-rt/lib/asan/asan_mac.cc @@ -24,7 +24,14 @@ #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mac.h" -#include <crt_externs.h> // for _NSGetArgv +#if !SANITIZER_IOS +#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron +#else +extern "C" { + extern char ***_NSGetArgv(void); +} +#endif + #include <dlfcn.h> // for dladdr() #include <mach-o/dyld.h> #include <mach-o/loader.h> @@ -40,19 +47,7 @@ namespace __asan { -void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { - ucontext_t *ucontext = (ucontext_t*)context; -# if SANITIZER_WORDSIZE == 64 - *pc = ucontext->uc_mcontext->__ss.__rip; - *bp = ucontext->uc_mcontext->__ss.__rbp; - *sp = ucontext->uc_mcontext->__ss.__rsp; -# else - *pc = ucontext->uc_mcontext->__ss.__eip; - *bp = ucontext->uc_mcontext->__ss.__ebp; - *sp = ucontext->uc_mcontext->__ss.__esp; -# endif // SANITIZER_WORDSIZE -} - +void InitializePlatformInterceptors() {} bool PlatformHasDifferentMemcpyAndMemmove() { // On OS X 10.7 memcpy() and memmove() are both resolved @@ -74,30 +69,27 @@ LowLevelAllocator allocator_for_env; // otherwise the corresponding "NAME=value" string is replaced with // |name_value|. void LeakyResetEnv(const char *name, const char *name_value) { - char ***env_ptr = _NSGetEnviron(); - CHECK(env_ptr); - char **environ = *env_ptr; - CHECK(environ); + char **env = GetEnviron(); uptr name_len = internal_strlen(name); - while (*environ != 0) { - uptr len = internal_strlen(*environ); + while (*env != 0) { + uptr len = internal_strlen(*env); if (len > name_len) { - const char *p = *environ; + const char *p = *env; if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { // Match. if (name_value) { // Replace the old value with the new one. - *environ = const_cast<char*>(name_value); + *env = const_cast<char*>(name_value); } else { // Shift the subsequent pointers back. - char **del = environ; + char **del = env; do { del[0] = del[1]; } while (*del++); } } } - environ++; + env++; } } @@ -107,6 +99,23 @@ void DisableReexec() { reexec_disabled = true; } +bool DyldNeedsEnvVariable() { +// If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if +// DYLD_INSERT_LIBRARIES is not set. + +#if SANITIZER_IOSSIM + // GetMacosVersion will not work for the simulator, whose kernel version + // is tied to the host. Use a weak linking hack for the simulator. + // This API was introduced in the same version of the OS as the dyld + // optimization. + + // Check for presence of a symbol that is available on OS X 10.11+, iOS 9.0+. + return (dlsym(RTLD_NEXT, "mach_memory_info") == nullptr); +#else + return (GetMacosVersion() <= MACOS_VERSION_YOSEMITE); +#endif +} + void MaybeReexec() { if (reexec_disabled) return; @@ -122,8 +131,10 @@ void MaybeReexec() { uptr fname_len = internal_strlen(info.dli_fname); const char *dylib_name = StripModuleName(info.dli_fname); uptr dylib_name_len = internal_strlen(dylib_name); - if (!dyld_insert_libraries || - !REAL(strstr)(dyld_insert_libraries, dylib_name)) { + + bool lib_is_in_env = + dyld_insert_libraries && REAL(strstr)(dyld_insert_libraries, dylib_name); + if (DyldNeedsEnvVariable() && !lib_is_in_env) { // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime // library. char program_name[1024]; @@ -160,6 +171,9 @@ void MaybeReexec() { CHECK("execv failed" && 0); } + if (!lib_is_in_env) + return; + // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove // the dylib from the environment variable, because interceptors are installed // and we don't want our children to inherit the variable. diff --git a/contrib/compiler-rt/lib/asan/asan_mapping.h b/contrib/compiler-rt/lib/asan/asan_mapping.h index 5cb011d..f9e1a52 100644 --- a/contrib/compiler-rt/lib/asan/asan_mapping.h +++ b/contrib/compiler-rt/lib/asan/asan_mapping.h @@ -98,9 +98,12 @@ static const u64 kDefaultShadowScale = 3; static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000 -static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kDefaultShadowOffset64 = 1ULL << 44; static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G. +static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000 +static const u64 kIosShadowOffset64 = 0x130000000; +static const u64 kIosSimShadowOffset32 = 1ULL << 30; +static const u64 kIosSimShadowOffset64 = kDefaultShadowOffset64; static const u64 kAArch64_ShadowOffset64 = 1ULL << 36; static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000; static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37; @@ -118,10 +121,12 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # define SHADOW_OFFSET kMIPS32_ShadowOffset32 # elif SANITIZER_FREEBSD # define SHADOW_OFFSET kFreeBSD_ShadowOffset32 -# elif SANITIZER_IOS -# define SHADOW_OFFSET kIosShadowOffset32 # elif SANITIZER_WINDOWS # define SHADOW_OFFSET kWindowsShadowOffset32 +# elif SANITIZER_IOSSIM +# define SHADOW_OFFSET kIosSimShadowOffset32 +# elif SANITIZER_IOS +# define SHADOW_OFFSET kIosShadowOffset32 # else # define SHADOW_OFFSET kDefaultShadowOffset32 # endif @@ -136,6 +141,10 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # define SHADOW_OFFSET kDefaultShadowOffset64 # elif defined(__mips64) # define SHADOW_OFFSET kMIPS64_ShadowOffset64 +# elif SANITIZER_IOSSIM +# define SHADOW_OFFSET kIosSimShadowOffset64 +# elif SANITIZER_IOS +# define SHADOW_OFFSET kIosShadowOffset64 # else # define SHADOW_OFFSET kDefaultShort64bitShadowOffset # endif diff --git a/contrib/compiler-rt/lib/asan/asan_poisoning.cc b/contrib/compiler-rt/lib/asan/asan_poisoning.cc index e2b1f4d..569d359 100644 --- a/contrib/compiler-rt/lib/asan/asan_poisoning.cc +++ b/contrib/compiler-rt/lib/asan/asan_poisoning.cc @@ -112,7 +112,7 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; - VPrintf(1, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr, + VPrintf(3, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr, (void *)end_addr); ShadowSegmentEndpoint beg(beg_addr); ShadowSegmentEndpoint end(end_addr); @@ -152,7 +152,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; - VPrintf(1, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr, + VPrintf(3, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr, (void *)end_addr); ShadowSegmentEndpoint beg(beg_addr); ShadowSegmentEndpoint end(end_addr); @@ -218,7 +218,7 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) { __asan::AddressIsPoisoned(__p + __size - 1))) { \ GET_CURRENT_PC_BP_SP; \ uptr __bad = __asan_region_is_poisoned(__p, __size); \ - __asan_report_error(pc, bp, sp, __bad, isWrite, __size);\ + __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\ } \ } while (false); \ diff --git a/contrib/compiler-rt/lib/asan/asan_poisoning.h b/contrib/compiler-rt/lib/asan/asan_poisoning.h index 3fc9464..6344225 100644 --- a/contrib/compiler-rt/lib/asan/asan_poisoning.h +++ b/contrib/compiler-rt/lib/asan/asan_poisoning.h @@ -64,7 +64,7 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, if (page_end != shadow_end) { REAL(memset)((void *)page_end, 0, shadow_end - page_end); } - ReserveShadowMemoryRange(page_beg, page_end - 1); + ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr); } } } diff --git a/contrib/compiler-rt/lib/asan/asan_posix.cc b/contrib/compiler-rt/lib/asan/asan_posix.cc index ad31458..2e857f6 100644 --- a/contrib/compiler-rt/lib/asan/asan_posix.cc +++ b/contrib/compiler-rt/lib/asan/asan_posix.cc @@ -21,6 +21,7 @@ #include "asan_report.h" #include "asan_stack.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_posix.h" #include "sanitizer_common/sanitizer_procmaps.h" #include <pthread.h> @@ -32,13 +33,6 @@ namespace __asan { -SignalContext SignalContext::Create(void *siginfo, void *context) { - uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr; - uptr pc, sp, bp; - GetPcSpBp(context, &pc, &sp, &bp); - return SignalContext(context, addr, pc, sp, bp); -} - void AsanOnSIGSEGV(int, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); int code = (int)((siginfo_t*)siginfo)->si_code; diff --git a/contrib/compiler-rt/lib/asan/asan_report.cc b/contrib/compiler-rt/lib/asan/asan_report.cc index 8706d5d..c1681e6 100644 --- a/contrib/compiler-rt/lib/asan/asan_report.cc +++ b/contrib/compiler-rt/lib/asan/asan_report.cc @@ -281,9 +281,8 @@ static void PrintGlobalLocation(InternalScopedString *str, str->append(":%d", g.location->column_no); } -bool DescribeAddressRelativeToGlobal(uptr addr, uptr size, - const __asan_global &g) { - if (!IsAddressNearGlobal(addr, g)) return false; +static void DescribeAddressRelativeToGlobal(uptr addr, uptr size, + const __asan_global &g) { InternalScopedString str(4096); Decorator d; str.append("%s", d.Location()); @@ -306,6 +305,26 @@ bool DescribeAddressRelativeToGlobal(uptr addr, uptr size, str.append("%s", d.EndLocation()); PrintGlobalNameIfASCII(&str, g); Printf("%s", str.data()); +} + +static bool DescribeAddressIfGlobal(uptr addr, uptr size, + const char *bug_type) { + // Assume address is close to at most four globals. + const int kMaxGlobalsInReport = 4; + __asan_global globals[kMaxGlobalsInReport]; + u32 reg_sites[kMaxGlobalsInReport]; + int globals_num = + GetGlobalsForAddress(addr, globals, reg_sites, ARRAY_SIZE(globals)); + if (globals_num == 0) + return false; + for (int i = 0; i < globals_num; i++) { + DescribeAddressRelativeToGlobal(addr, size, globals[i]); + if (0 == internal_strcmp(bug_type, "initialization-order-fiasco") && + reg_sites[i]) { + Printf(" registered at:\n"); + StackDepotGet(reg_sites[i]).Print(); + } + } return true; } @@ -551,12 +570,12 @@ void DescribeHeapAddress(uptr addr, uptr access_size) { DescribeThread(alloc_thread); } -void DescribeAddress(uptr addr, uptr access_size) { +static void DescribeAddress(uptr addr, uptr access_size, const char *bug_type) { // Check if this is shadow or shadow gap. if (DescribeAddressIfShadow(addr)) return; CHECK(AddrIsInMem(addr)); - if (DescribeAddressIfGlobal(addr, access_size)) + if (DescribeAddressIfGlobal(addr, access_size, bug_type)) return; if (DescribeAddressIfStack(addr, access_size)) return; @@ -578,6 +597,11 @@ void DescribeThread(AsanThreadContext *context) { InternalScopedString str(1024); str.append("Thread T%d%s", context->tid, ThreadNameWithParenthesis(context->tid, tname, sizeof(tname))); + if (context->parent_tid == kInvalidTid) { + str.append(" created by unknown thread\n"); + Printf("%s", str.data()); + return; + } str.append( " created by T%d%s here:\n", context->parent_tid, ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); @@ -805,8 +829,8 @@ void ReportStringFunctionMemoryRangesOverlap(const char *function, bug_type, offset1, offset1 + length1, offset2, offset2 + length2); Printf("%s", d.EndWarning()); stack->Print(); - DescribeAddress((uptr)offset1, length1); - DescribeAddress((uptr)offset2, length2); + DescribeAddress((uptr)offset1, length1, bug_type); + DescribeAddress((uptr)offset2, length2, bug_type); ReportErrorSummary(bug_type, stack); } @@ -819,7 +843,7 @@ void ReportStringFunctionSizeOverflow(uptr offset, uptr size, Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size); Printf("%s", d.EndWarning()); stack->Print(); - DescribeAddress(offset, size); + DescribeAddress(offset, size, bug_type); ReportErrorSummary(bug_type, stack); } @@ -834,6 +858,9 @@ void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, " old_mid : %p\n" " new_mid : %p\n", beg, end, old_mid, new_mid); + uptr granularity = SHADOW_GRANULARITY; + if (!IsAligned(beg, granularity)) + Report("ERROR: beg is not aligned by %d\n", granularity); stack->Print(); ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack); } @@ -871,15 +898,16 @@ void ReportODRViolation(const __asan_global *g1, u32 stack_id1, static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, uptr a1, uptr a2) { ScopedInErrorReport in_report; + const char *bug_type = "invalid-pointer-pair"; Decorator d; Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1, a2); Printf("%s", d.EndWarning()); GET_STACK_TRACE_FATAL(pc, bp); stack.Print(); - DescribeAddress(a1, 1); - DescribeAddress(a2, 1); - ReportErrorSummary("invalid-pointer-pair", &stack); + DescribeAddress(a1, 1, bug_type); + DescribeAddress(a2, 1, bug_type); + ReportErrorSummary(bug_type, &stack); } static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { @@ -936,9 +964,18 @@ void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, using namespace __asan; // NOLINT void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, - uptr access_size) { + uptr access_size, u32 exp) { ENABLE_FRAME_POINTER; + // Optimization experiments. + // The experiments can be used to evaluate potential optimizations that remove + // instrumentation (assess false negatives). Instead of completely removing + // some instrumentation, compiler can emit special calls into runtime + // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass + // mask of experiments (exp). + // The reaction to a non-zero value of exp is to be defined. + (void)exp; + // Determine the error type. const char *bug_descr = "unknown-crash"; if (AddrIsInMem(addr)) { @@ -1017,7 +1054,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, GET_STACK_TRACE_FATAL(pc, bp); stack.Print(); - DescribeAddress(addr, access_size); + DescribeAddress(addr, access_size, bug_descr); ReportErrorSummary(bug_descr, &stack); PrintShadowMemoryForAddress(addr); } @@ -1035,7 +1072,7 @@ void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) { void __asan_describe_address(uptr addr) { // Thread registry must be locked while we're describing an address. asanThreadRegistry().Lock(); - DescribeAddress(addr, 1); + DescribeAddress(addr, 1, ""); asanThreadRegistry().Unlock(); } diff --git a/contrib/compiler-rt/lib/asan/asan_report.h b/contrib/compiler-rt/lib/asan/asan_report.h index 029c914..e2786b0 100644 --- a/contrib/compiler-rt/lib/asan/asan_report.h +++ b/contrib/compiler-rt/lib/asan/asan_report.h @@ -33,22 +33,19 @@ struct AddressDescription { const char *region_kind; }; +// Returns the number of globals close to the provided address and copies +// them to "globals" array. +int GetGlobalsForAddress(uptr addr, __asan_global *globals, u32 *reg_sites, + int max_globals); +bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr); // The following functions prints address description depending // on the memory type (shadow/heap/stack/global). void DescribeHeapAddress(uptr addr, uptr access_size); -bool DescribeAddressIfGlobal(uptr addr, uptr access_size); -bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, - const __asan_global &g); -bool IsAddressNearGlobal(uptr addr, const __asan_global &g); -bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr); bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr, bool print = true); bool ParseFrameDescription(const char *frame_descr, InternalMmapVector<StackVarDescr> *vars); bool DescribeAddressIfStack(uptr addr, uptr access_size); -// Determines memory type on its own. -void DescribeAddress(uptr addr, uptr access_size); - void DescribeThread(AsanThreadContext *context); // Different kinds of error reports. diff --git a/contrib/compiler-rt/lib/asan/asan_rtl.cc b/contrib/compiler-rt/lib/asan/asan_rtl.cc index 9126e71..a8d92b9 100644 --- a/contrib/compiler-rt/lib/asan/asan_rtl.cc +++ b/contrib/compiler-rt/lib/asan/asan_rtl.cc @@ -28,6 +28,8 @@ #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_symbolizer.h" #include "lsan/lsan_common.h" +#include "ubsan/ubsan_init.h" +#include "ubsan/ubsan_platform.h" int __asan_option_detect_stack_use_after_return; // Global interface symbol. uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan. @@ -87,12 +89,12 @@ void ShowStatsAndAbort() { // ---------------------- mmap -------------------- {{{1 // Reserve memory range [beg, end]. // We need to use inclusive range because end+1 may not be representable. -void ReserveShadowMemoryRange(uptr beg, uptr end) { +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { CHECK_EQ((beg % GetPageSizeCached()), 0); CHECK_EQ(((end + 1) % GetPageSizeCached()), 0); uptr size = end - beg + 1; DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. - void *res = MmapFixedNoReserve(beg, size); + void *res = MmapFixedNoReserve(beg, size, name); if (res != (void*)beg) { Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " "Perhaps you're using ulimit -v\n", size); @@ -112,11 +114,15 @@ static void OnLowLevelAllocate(uptr ptr, uptr size) { // -------------------------- Run-time entry ------------------- {{{1 // exported functions #define ASAN_REPORT_ERROR(type, is_write, size) \ -extern "C" NOINLINE INTERFACE_ATTRIBUTE \ -void __asan_report_ ## type ## size(uptr addr); \ -void __asan_report_ ## type ## size(uptr addr) { \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +void __asan_report_ ## type ## size(uptr addr) { \ + GET_CALLER_PC_BP_SP; \ + __asan_report_error(pc, bp, sp, addr, is_write, size, 0); \ +} \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) { \ GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size); \ + __asan_report_error(pc, bp, sp, addr, is_write, size, exp); \ } ASAN_REPORT_ERROR(load, false, 1) @@ -132,18 +138,20 @@ ASAN_REPORT_ERROR(store, true, 16) #define ASAN_REPORT_ERROR_N(type, is_write) \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ -void __asan_report_ ## type ## _n(uptr addr, uptr size); \ void __asan_report_ ## type ## _n(uptr addr, uptr size) { \ GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size); \ + __asan_report_error(pc, bp, sp, addr, is_write, size, 0); \ +} \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) { \ + GET_CALLER_PC_BP_SP; \ + __asan_report_error(pc, bp, sp, addr, is_write, size, exp); \ } ASAN_REPORT_ERROR_N(load, false) ASAN_REPORT_ERROR_N(store, true) -#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \ - extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_##type##size(uptr addr); \ - void __asan_##type##size(uptr addr) { \ +#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg) \ uptr sp = MEM_TO_SHADOW(addr); \ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \ : *reinterpret_cast<u16 *>(sp); \ @@ -155,10 +163,19 @@ ASAN_REPORT_ERROR_N(store, true) *__asan_test_only_reported_buggy_pointer = addr; \ } else { \ GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size); \ + __asan_report_error(pc, bp, sp, addr, is_write, size, exp_arg); \ } \ } \ - } \ + } + +#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \ + extern "C" NOINLINE INTERFACE_ATTRIBUTE \ + void __asan_##type##size(uptr addr) { \ + ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0) \ + } \ + extern "C" NOINLINE INTERFACE_ATTRIBUTE \ + void __asan_exp_##type##size(uptr addr, u32 exp) { \ + ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp) \ } ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1) @@ -173,18 +190,38 @@ ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16) extern "C" -NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN(uptr addr, uptr size) { +NOINLINE INTERFACE_ATTRIBUTE +void __asan_loadN(uptr addr, uptr size) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; - __asan_report_error(pc, bp, sp, addr, false, size); + __asan_report_error(pc, bp, sp, addr, false, size, 0); } } extern "C" -NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN(uptr addr, uptr size) { +NOINLINE INTERFACE_ATTRIBUTE +void __asan_exp_loadN(uptr addr, uptr size, u32 exp) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; - __asan_report_error(pc, bp, sp, addr, true, size); + __asan_report_error(pc, bp, sp, addr, false, size, exp); + } +} + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE +void __asan_storeN(uptr addr, uptr size) { + if (__asan_region_is_poisoned(addr, size)) { + GET_CALLER_PC_BP_SP; + __asan_report_error(pc, bp, sp, addr, true, size, 0); + } +} + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE +void __asan_exp_storeN(uptr addr, uptr size, u32 exp) { + if (__asan_region_is_poisoned(addr, size)) { + GET_CALLER_PC_BP_SP; + __asan_report_error(pc, bp, sp, addr, true, size, exp); } } @@ -203,26 +240,40 @@ static NOINLINE void force_interface_symbols() { case 3: __asan_report_load4(0); break; case 4: __asan_report_load8(0); break; case 5: __asan_report_load16(0); break; - case 6: __asan_report_store1(0); break; - case 7: __asan_report_store2(0); break; - case 8: __asan_report_store4(0); break; - case 9: __asan_report_store8(0); break; - case 10: __asan_report_store16(0); break; - case 12: __asan_register_globals(0, 0); break; - case 13: __asan_unregister_globals(0, 0); break; - case 14: __asan_set_death_callback(0); break; - case 15: __asan_set_error_report_callback(0); break; - case 16: __asan_handle_no_return(); break; - case 17: __asan_address_is_poisoned(0); break; - case 25: __asan_poison_memory_region(0, 0); break; - case 26: __asan_unpoison_memory_region(0, 0); break; - case 27: __asan_set_error_exit_code(0); break; - case 30: __asan_before_dynamic_init(0); break; - case 31: __asan_after_dynamic_init(); break; - case 32: __asan_poison_stack_memory(0, 0); break; - case 33: __asan_unpoison_stack_memory(0, 0); break; - case 34: __asan_region_is_poisoned(0, 0); break; - case 35: __asan_describe_address(0); break; + case 6: __asan_report_load_n(0, 0); break; + case 7: __asan_report_store1(0); break; + case 8: __asan_report_store2(0); break; + case 9: __asan_report_store4(0); break; + case 10: __asan_report_store8(0); break; + case 11: __asan_report_store16(0); break; + case 12: __asan_report_store_n(0, 0); break; + case 13: __asan_report_exp_load1(0, 0); break; + case 14: __asan_report_exp_load2(0, 0); break; + case 15: __asan_report_exp_load4(0, 0); break; + case 16: __asan_report_exp_load8(0, 0); break; + case 17: __asan_report_exp_load16(0, 0); break; + case 18: __asan_report_exp_load_n(0, 0, 0); break; + case 19: __asan_report_exp_store1(0, 0); break; + case 20: __asan_report_exp_store2(0, 0); break; + case 21: __asan_report_exp_store4(0, 0); break; + case 22: __asan_report_exp_store8(0, 0); break; + case 23: __asan_report_exp_store16(0, 0); break; + case 24: __asan_report_exp_store_n(0, 0, 0); break; + case 25: __asan_register_globals(0, 0); break; + case 26: __asan_unregister_globals(0, 0); break; + case 27: __asan_set_death_callback(0); break; + case 28: __asan_set_error_report_callback(0); break; + case 29: __asan_handle_no_return(); break; + case 30: __asan_address_is_poisoned(0); break; + case 31: __asan_poison_memory_region(0, 0); break; + case 32: __asan_unpoison_memory_region(0, 0); break; + case 33: __asan_set_error_exit_code(0); break; + case 34: __asan_before_dynamic_init(0); break; + case 35: __asan_after_dynamic_init(); break; + case 36: __asan_poison_stack_memory(0, 0); break; + case 37: __asan_unpoison_stack_memory(0, 0); break; + case 38: __asan_region_is_poisoned(0, 0); break; + case 39: __asan_describe_address(0); break; } } @@ -246,9 +297,9 @@ static void InitializeHighMemEnd() { CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0); } -static void ProtectGap(uptr a, uptr size) { - void *res = Mprotect(a, size); - if (a == (uptr)res) +static void ProtectGap(uptr addr, uptr size) { + void *res = MmapNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) return; Report("ERROR: Failed to protect the shadow gap. " "ASan cannot proceed correctly. ABORTING.\n"); @@ -296,9 +347,9 @@ static void PrintAddressSpaceLayout() { Printf("malloc_context_size=%zu\n", (uptr)common_flags()->malloc_context_size); - Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE); - Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY); - Printf("SHADOW_OFFSET: %zx\n", (uptr)SHADOW_OFFSET); + Printf("SHADOW_SCALE: %d\n", (int)SHADOW_SCALE); + Printf("SHADOW_GRANULARITY: %d\n", (int)SHADOW_GRANULARITY); + Printf("SHADOW_OFFSET: 0x%zx\n", (uptr)SHADOW_OFFSET); CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7); if (kMidMemBeg) CHECK(kMidShadowBeg > kLowShadowEnd && @@ -316,6 +367,11 @@ static void AsanInitInternal() { // initialization steps look at flags(). InitializeFlags(); + CacheBinaryName(); + + AsanCheckIncompatibleRT(); + AsanCheckDynamicRTPrereqs(); + SetCanPoisonMemory(flags()->poison_heap); SetMallocContextSize(common_flags()->malloc_context_size); @@ -371,9 +427,9 @@ static void AsanInitInternal() { if (full_shadow_is_available) { // mmap the low shadow plus at least one page at the left. if (kLowShadowBeg) - ReserveShadowMemoryRange(shadow_start, kLowShadowEnd); + ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); // mmap the high shadow. - ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd); + ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); // protect the gap. ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); @@ -382,11 +438,11 @@ static void AsanInitInternal() { MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { CHECK(kLowShadowBeg != kLowShadowEnd); // mmap the low shadow plus at least one page at the left. - ReserveShadowMemoryRange(shadow_start, kLowShadowEnd); + ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); // mmap the mid shadow. - ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd); + ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow"); // mmap the high shadow. - ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd); + ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); // protect the gaps. ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); @@ -446,6 +502,10 @@ static void AsanInitInternal() { } #endif // CAN_SANITIZE_LEAKS +#if CAN_SANITIZE_UB + __ubsan::InitAsPlugin(); +#endif + InitializeSuppressions(); VReport(1, "AddressSanitizer Init done\n"); @@ -459,13 +519,11 @@ void AsanInitFromRtl() { #if ASAN_DYNAMIC // Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable -// (and thus normal initializer from .preinit_array haven't run). +// (and thus normal initializers from .preinit_array or modules haven't run). class AsanInitializer { public: // NOLINT AsanInitializer() { - AsanCheckIncompatibleRT(); - AsanCheckDynamicRTPrereqs(); AsanInitFromRtl(); } }; @@ -517,7 +575,6 @@ void NOINLINE __asan_set_death_callback(void (*callback)(void)) { // Initialize as requested from instrumented application code. // We use this call as a trigger to wake up ASan from deactivated state. void __asan_init() { - AsanCheckIncompatibleRT(); AsanActivate(); AsanInitInternal(); } diff --git a/contrib/compiler-rt/lib/asan/asan_stats.cc b/contrib/compiler-rt/lib/asan/asan_stats.cc index a78b7b1..b8c68c3 100644 --- a/contrib/compiler-rt/lib/asan/asan_stats.cc +++ b/contrib/compiler-rt/lib/asan/asan_stats.cc @@ -51,12 +51,8 @@ void AsanStats::Print() { (mmaped-munmaped)>>20, mmaped>>20, munmaped>>20, mmaps, munmaps); - PrintMallocStatsArray(" mmaps by size class: ", mmaped_by_size); PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size); - PrintMallocStatsArray(" frees by size class: ", freed_by_size); - PrintMallocStatsArray(" rfrees by size class: ", really_freed_by_size); - Printf("Stats: malloc large: %zu small slow: %zu\n", - malloc_large, malloc_small_slow); + Printf("Stats: malloc large: %zu\n", malloc_large); } void AsanStats::MergeFrom(const AsanStats *stats) { @@ -161,8 +157,7 @@ uptr __sanitizer_get_free_bytes() { GetAccumulatedStats(&stats); uptr total_free = stats.mmaped - stats.munmaped - + stats.really_freed - + stats.really_freed_redzones; + + stats.really_freed; uptr total_used = stats.malloced + stats.malloced_redzones; // Return sane value if total_free < total_used due to racy diff --git a/contrib/compiler-rt/lib/asan/asan_stats.h b/contrib/compiler-rt/lib/asan/asan_stats.h index c66848d..4605135 100644 --- a/contrib/compiler-rt/lib/asan/asan_stats.h +++ b/contrib/compiler-rt/lib/asan/asan_stats.h @@ -32,20 +32,14 @@ struct AsanStats { uptr freed; uptr real_frees; uptr really_freed; - uptr really_freed_redzones; uptr reallocs; uptr realloced; uptr mmaps; uptr mmaped; uptr munmaps; uptr munmaped; - uptr mmaped_by_size[kNumberOfSizeClasses]; - uptr malloced_by_size[kNumberOfSizeClasses]; - uptr freed_by_size[kNumberOfSizeClasses]; - uptr really_freed_by_size[kNumberOfSizeClasses]; - uptr malloc_large; - uptr malloc_small_slow; + uptr malloced_by_size[kNumberOfSizeClasses]; // Ctor for global AsanStats (accumulated stats for dead threads). explicit AsanStats(LinkerInitialized) { } diff --git a/contrib/compiler-rt/lib/asan/asan_suppressions.cc b/contrib/compiler-rt/lib/asan/asan_suppressions.cc index 62198ae..41887b5 100644 --- a/contrib/compiler-rt/lib/asan/asan_suppressions.cc +++ b/contrib/compiler-rt/lib/asan/asan_suppressions.cc @@ -26,14 +26,28 @@ static SuppressionContext *suppression_ctx = nullptr; static const char kInterceptorName[] = "interceptor_name"; static const char kInterceptorViaFunction[] = "interceptor_via_fun"; static const char kInterceptorViaLibrary[] = "interceptor_via_lib"; +static const char kODRViolation[] = "odr_violation"; static const char *kSuppressionTypes[] = { - kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary}; + kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary, + kODRViolation}; + +extern "C" { +#if SANITIZER_SUPPORTS_WEAK_HOOKS +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +const char *__asan_default_suppressions(); +#else +// No week hooks, provide empty implementation. +const char *__asan_default_suppressions() { return ""; } +#endif // SANITIZER_SUPPORTS_WEAK_HOOKS +} // extern "C" void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); suppression_ctx = new (suppression_placeholder) // NOLINT SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); + if (&__asan_default_suppressions) + suppression_ctx->Parse(__asan_default_suppressions()); } bool IsInterceptorSuppressed(const char *interceptor_name) { @@ -49,6 +63,13 @@ bool HaveStackTraceBasedSuppressions() { suppression_ctx->HasSuppressionType(kInterceptorViaLibrary); } +bool IsODRViolationSuppressed(const char *global_var_name) { + CHECK(suppression_ctx); + Suppression *s; + // Match "odr_violation" suppressions. + return suppression_ctx->Match(global_var_name, kODRViolation, &s); +} + bool IsStackTraceSuppressed(const StackTrace *stack) { if (!HaveStackTraceBasedSuppressions()) return false; @@ -60,14 +81,10 @@ bool IsStackTraceSuppressed(const StackTrace *stack) { uptr addr = stack->trace[i]; if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) { - const char *module_name; - uptr module_offset; // Match "interceptor_via_lib" suppressions. - if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name, - &module_offset) && - suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) { - return true; - } + if (const char *module_name = symbolizer->GetModuleNameForPc(addr)) + if (suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) + return true; } if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) { diff --git a/contrib/compiler-rt/lib/asan/asan_suppressions.h b/contrib/compiler-rt/lib/asan/asan_suppressions.h index cd7ba2e..5246b4b 100644 --- a/contrib/compiler-rt/lib/asan/asan_suppressions.h +++ b/contrib/compiler-rt/lib/asan/asan_suppressions.h @@ -23,6 +23,7 @@ void InitializeSuppressions(); bool IsInterceptorSuppressed(const char *interceptor_name); bool HaveStackTraceBasedSuppressions(); bool IsStackTraceSuppressed(const StackTrace *stack); +bool IsODRViolationSuppressed(const char *global_var_name); } // namespace __asan diff --git a/contrib/compiler-rt/lib/asan/asan_thread.h b/contrib/compiler-rt/lib/asan/asan_thread.h index 9da136c..50acfc4 100644 --- a/contrib/compiler-rt/lib/asan/asan_thread.h +++ b/contrib/compiler-rt/lib/asan/asan_thread.h @@ -34,19 +34,16 @@ class AsanThread; class AsanThreadContext : public ThreadContextBase { public: explicit AsanThreadContext(int tid) - : ThreadContextBase(tid), - announced(false), - destructor_iterations(kPthreadDestructorIterations), - stack_id(0), - thread(0) { - } + : ThreadContextBase(tid), announced(false), + destructor_iterations(GetPthreadDestructorIterations()), stack_id(0), + thread(0) {} bool announced; u8 destructor_iterations; u32 stack_id; AsanThread *thread; - void OnCreated(void *arg); - void OnFinished(); + void OnCreated(void *arg) override; + void OnFinished() override; }; // AsanThreadContext objects are never freed, so we need many of them. diff --git a/contrib/compiler-rt/lib/asan/asan_win.cc b/contrib/compiler-rt/lib/asan/asan_win.cc index 693f0bc..addb3d4 100644 --- a/contrib/compiler-rt/lib/asan/asan_win.cc +++ b/contrib/compiler-rt/lib/asan/asan_win.cc @@ -22,21 +22,134 @@ #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_report.h" +#include "asan_stack.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" +using namespace __asan; // NOLINT + extern "C" { - SANITIZER_INTERFACE_ATTRIBUTE - int __asan_should_detect_stack_use_after_return() { - __asan_init(); - return __asan_option_detect_stack_use_after_return; - } +SANITIZER_INTERFACE_ATTRIBUTE +int __asan_should_detect_stack_use_after_return() { + __asan_init(); + return __asan_option_detect_stack_use_after_return; +} + +// -------------------- A workaround for the abscence of weak symbols ----- {{{ +// We don't have a direct equivalent of weak symbols when using MSVC, but we can +// use the /alternatename directive to tell the linker to default a specific +// symbol to a specific value, which works nicely for allocator hooks and +// __asan_default_options(). +void __sanitizer_default_malloc_hook(void *ptr, uptr size) { } +void __sanitizer_default_free_hook(void *ptr) { } +const char* __asan_default_default_options() { return ""; } +const char* __asan_default_default_suppressions() { return ""; } +void __asan_default_on_error() {} +#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook") // NOLINT +#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook") // NOLINT +#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT +#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT +#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT +// }}} +} // extern "C" + +// ---------------------- Windows-specific inteceptors ---------------- {{{ +INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { + CHECK(REAL(RaiseException)); + __asan_handle_no_return(); + REAL(RaiseException)(a, b, c, d); +} + +INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) { + CHECK(REAL(_except_handler3)); + __asan_handle_no_return(); + return REAL(_except_handler3)(a, b, c, d); +} + +#if ASAN_DYNAMIC +// This handler is named differently in -MT and -MD CRTs. +#define _except_handler4 _except_handler4_common +#endif +INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { + CHECK(REAL(_except_handler4)); + __asan_handle_no_return(); + return REAL(_except_handler4)(a, b, c, d); +} + +static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { + AsanThread *t = (AsanThread*)arg; + SetCurrentThread(t); + return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr); +} + +INTERCEPTOR_WINAPI(DWORD, CreateThread, + void* security, uptr stack_size, + DWORD (__stdcall *start_routine)(void*), void* arg, + DWORD thr_flags, void* tid) { + // Strict init-order checking is thread-hostile. + if (flags()->strict_init_order) + StopInitOrderChecking(); + GET_STACK_TRACE_THREAD; + // FIXME: The CreateThread interceptor is not the same as a pthread_create + // one. This is a bandaid fix for PR22025. + bool detached = false; // FIXME: how can we determine it on Windows? + u32 current_tid = GetCurrentTidOrInvalid(); + AsanThread *t = + AsanThread::Create(start_routine, arg, current_tid, &stack, detached); + return REAL(CreateThread)(security, stack_size, + asan_thread_start, t, thr_flags, tid); +} + +namespace { +BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED); + +void EnsureWorkerThreadRegistered() { + // FIXME: GetCurrentThread relies on TSD, which might not play well with + // system thread pools. We might want to use something like reference + // counting to zero out GetCurrentThread() underlying storage when the last + // work item finishes? Or can we disable reclaiming of threads in the pool? + BlockingMutexLock l(&mu_for_thread_tracking); + if (__asan::GetCurrentThread()) + return; + + AsanThread *t = AsanThread::Create( + /* start_routine */ nullptr, /* arg */ nullptr, + /* parent_tid */ -1, /* stack */ nullptr, /* detached */ true); + t->Init(); + asanThreadRegistry().StartThread(t->tid(), 0, 0); + SetCurrentThread(t); +} +} // namespace + +INTERCEPTOR_WINAPI(DWORD, NtWaitForWorkViaWorkerFactory, DWORD a, DWORD b) { + // NtWaitForWorkViaWorkerFactory is called from system worker pool threads to + // query work scheduled by BindIoCompletionCallback, QueueUserWorkItem, etc. + // System worker pool threads are created at arbitraty point in time and + // without using CreateThread, so we wrap NtWaitForWorkViaWorkerFactory + // instead and don't register a specific parent_tid/stack. + EnsureWorkerThreadRegistered(); + return REAL(NtWaitForWorkViaWorkerFactory)(a, b); } +// }}} + namespace __asan { -// ---------------------- TSD ---------------- {{{1 +void InitializePlatformInterceptors() { + ASAN_INTERCEPT_FUNC(CreateThread); + ASAN_INTERCEPT_FUNC(RaiseException); + ASAN_INTERCEPT_FUNC(_except_handler3); + ASAN_INTERCEPT_FUNC(_except_handler4); + + // NtWaitForWorkViaWorkerFactory is always linked dynamically. + CHECK(::__interception::OverrideFunction( + "NtWaitForWorkViaWorkerFactory", + (uptr)WRAP(NtWaitForWorkViaWorkerFactory), + (uptr *)&REAL(NtWaitForWorkViaWorkerFactory))); +} + +// ---------------------- TSD ---------------- {{{ static bool tsd_key_inited = false; static __declspec(thread) void *fake_tsd = 0; @@ -59,7 +172,9 @@ void AsanTSDSet(void *tsd) { void PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); } -// ---------------------- Various stuff ---------------- {{{1 +// }}} + +// ---------------------- Various stuff ---------------- {{{ void DisableReexec() { // No need to re-exec on Windows. } @@ -93,23 +208,6 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) { static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; -SignalContext SignalContext::Create(void *siginfo, void *context) { - EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo; - CONTEXT *context_record = (CONTEXT*)context; - - uptr pc = (uptr)exception_record->ExceptionAddress; -#ifdef _WIN64 - uptr bp = (uptr)context_record->Rbp; - uptr sp = (uptr)context_record->Rsp; -#else - uptr bp = (uptr)context_record->Ebp; - uptr sp = (uptr)context_record->Esp; -#endif - uptr access_addr = exception_record->ExceptionInformation[1]; - - return SignalContext(context, access_addr, pc, sp, bp); -} - static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { EXCEPTION_RECORD *exception_record = info->ExceptionRecord; CONTEXT *context = info->ContextRecord; @@ -162,7 +260,7 @@ int __asan_set_seh_filter() { static __declspec(allocate(".CRT$XIZ")) int (*__intercept_seh)() = __asan_set_seh_filter; #endif - +// }}} } // namespace __asan #endif // _WIN32 diff --git a/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc index 5d39e33..b77f181 100644 --- a/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc +++ b/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc @@ -303,8 +303,8 @@ INTERFACE_FUNCTION(__sanitizer_cov_init) INTERFACE_FUNCTION(__sanitizer_cov_module_init) INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block) INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter) +INTERFACE_FUNCTION(__sanitizer_cov_trace_cmp) INTERFACE_FUNCTION(__sanitizer_cov_with_check) -INTERFACE_FUNCTION(__sanitizer_free_hook) INTERFACE_FUNCTION(__sanitizer_get_allocated_size) INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes) @@ -314,13 +314,14 @@ INTERFACE_FUNCTION(__sanitizer_get_heap_size) INTERFACE_FUNCTION(__sanitizer_get_ownership) INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage) INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) -INTERFACE_FUNCTION(__sanitizer_malloc_hook) INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) INTERFACE_FUNCTION(__sanitizer_print_stack_trace) INTERFACE_FUNCTION(__sanitizer_ptr_cmp) INTERFACE_FUNCTION(__sanitizer_ptr_sub) INTERFACE_FUNCTION(__sanitizer_report_error_summary) INTERFACE_FUNCTION(__sanitizer_reset_coverage) +INTERFACE_FUNCTION(__sanitizer_get_number_of_counters) +INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters) INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify) INTERFACE_FUNCTION(__sanitizer_set_death_callback) INTERFACE_FUNCTION(__sanitizer_set_report_path) @@ -380,11 +381,15 @@ INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT INTERCEPT_LIBRARY_FUNCTION(strchr); INTERCEPT_LIBRARY_FUNCTION(strcmp); INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT +INTERCEPT_LIBRARY_FUNCTION(strcspn); INTERCEPT_LIBRARY_FUNCTION(strlen); INTERCEPT_LIBRARY_FUNCTION(strncat); INTERCEPT_LIBRARY_FUNCTION(strncmp); INTERCEPT_LIBRARY_FUNCTION(strncpy); INTERCEPT_LIBRARY_FUNCTION(strnlen); +INTERCEPT_LIBRARY_FUNCTION(strpbrk); +INTERCEPT_LIBRARY_FUNCTION(strspn); +INTERCEPT_LIBRARY_FUNCTION(strstr); INTERCEPT_LIBRARY_FUNCTION(strtol); INTERCEPT_LIBRARY_FUNCTION(wcslen); diff --git a/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc b/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc index 1945614..d59f9f5 100644 --- a/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ b/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -15,7 +15,8 @@ // // This includes: // - forwarding the detect_stack_use_after_return runtime option -// - installing a custom SEH handler +// - working around deficiencies of the MD runtime +// - installing a custom SEH handlerx // //===----------------------------------------------------------------------===// @@ -24,9 +25,13 @@ // simplifies the build procedure. #ifdef ASAN_DYNAMIC_RUNTIME_THUNK #include <windows.h> -#include <psapi.h> -extern "C" { +// First, declare CRT sections we'll be using in this file +#pragma section(".CRT$XID", long, read) // NOLINT +#pragma section(".CRT$XIZ", long, read) // NOLINT +#pragma section(".CRT$XTW", long, read) // NOLINT +#pragma section(".CRT$XTY", long, read) // NOLINT + //////////////////////////////////////////////////////////////////////////////// // Define a copy of __asan_option_detect_stack_use_after_return that should be // used when linking an MD runtime with a set of object files on Windows. @@ -38,82 +43,55 @@ extern "C" { // with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows // just to work around this issue, let's clone the a variable that is // constant after initialization anyways. +extern "C" { __declspec(dllimport) int __asan_should_detect_stack_use_after_return(); int __asan_option_detect_stack_use_after_return = __asan_should_detect_stack_use_after_return(); } //////////////////////////////////////////////////////////////////////////////// -// For some reason, the MD CRT doesn't call the C/C++ terminators as MT does. -// To work around this, for each DLL we schedule a call to -// UnregisterGlobalsInRange atexit() specifying the address range of the DLL -// image to unregister globals in that range. We don't do the same -// for the main module (.exe) as the asan_globals.cc allocator is destroyed -// by the time UnregisterGlobalsInRange is executed. -// See PR22545 for the details. -namespace __asan { -__declspec(dllimport) -void UnregisterGlobalsInRange(void *beg, void *end); -} +// For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL +// unload or on exit. ASan relies on LLVM global_dtors to call +// __asan_unregister_globals on these events, which unfortunately doesn't work +// with the MD runtime, see PR22545 for the details. +// To work around this, for each DLL we schedule a call to UnregisterGlobals +// using atexit() that calls a small subset of C terminators +// where LLVM global_dtors is placed. Fingers crossed, no other C terminators +// are there. +extern "C" void __cdecl _initterm(void *a, void *b); namespace { -void *this_module_base, *this_module_end; +__declspec(allocate(".CRT$XTW")) void* before_global_dtors = 0; +__declspec(allocate(".CRT$XTY")) void* after_global_dtors = 0; void UnregisterGlobals() { - __asan::UnregisterGlobalsInRange(this_module_base, this_module_end); + _initterm(&before_global_dtors, &after_global_dtors); } int ScheduleUnregisterGlobals() { - HMODULE this_module = 0; - // Increments the reference counter of the DLL module, so need to call - // FreeLibrary later. - if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - (LPCTSTR)&UnregisterGlobals, &this_module)) - return 1; - - // Skip the main module. - if (this_module == GetModuleHandle(0)) - return 0; - - MODULEINFO mi; - bool success = - GetModuleInformation(GetCurrentProcess(), this_module, &mi, sizeof(mi)); - if (!FreeLibrary(this_module)) - return 2; - if (!success) - return 3; - - this_module_base = mi.lpBaseOfDll; - this_module_end = (char*)mi.lpBaseOfDll + mi.SizeOfImage; - return atexit(UnregisterGlobals); } -} // namespace - -/////////////////////////////////////////////////////////////////////////////// -// ASan SEH handling. -extern "C" __declspec(dllimport) int __asan_set_seh_filter(); -static int SetSEHFilter() { return __asan_set_seh_filter(); } -/////////////////////////////////////////////////////////////////////////////// -// We schedule some work at start-up by placing callbacks to our code to the -// list of CRT C initializers. -// -// First, declare sections we'll be using: -#pragma section(".CRT$XID", long, read) // NOLINT -#pragma section(".CRT$XIZ", long, read) // NOLINT - -// We need to call 'atexit(UnregisterGlobals);' after atexit() is initialized -// (.CRT$XIC) but before the C++ constructors (.CRT$XCA). +// We need to call 'atexit(UnregisterGlobals);' as early as possible, but after +// atexit() is initialized (.CRT$XIC). As this is executed before C++ +// initializers (think ctors for globals), UnregisterGlobals gets executed after +// dtors for C++ globals. __declspec(allocate(".CRT$XID")) -static int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; +int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// ASan SEH handling. // We need to set the ASan-specific SEH handler at the end of CRT initialization // of each module (see also asan_win.cc). -// +extern "C" { +__declspec(dllimport) int __asan_set_seh_filter(); +static int SetSEHFilter() { return __asan_set_seh_filter(); } + // Unfortunately, putting a pointer to __asan_set_seh_filter into // __asan_intercept_seh gets optimized out, so we have to use an extra function. -extern "C" __declspec(allocate(".CRT$XIZ")) -int (*__asan_seh_interceptor)() = SetSEHFilter; +__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter; +} #endif // ASAN_DYNAMIC_RUNTIME_THUNK diff --git a/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py b/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py index 59fceaa..b9d3ad3 100755 --- a/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py +++ b/contrib/compiler-rt/lib/asan/scripts/asan_symbolize.py @@ -23,6 +23,7 @@ sysroot_path = None binary_name_filter = None fix_filename_patterns = None logfile = sys.stdin +allow_system_symbolizer = True # FIXME: merge the code that calls fix_filename(). def fix_filename(file_name): @@ -392,6 +393,8 @@ class SymbolizationLoop(object): [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]]) result = symbolizers[binary].symbolize(addr, binary, offset) if result is None: + if not allow_system_symbolizer: + raise Exception('Failed to launch or use llvm-symbolizer.') # Initialize system symbolizer only if other symbolizers failed. symbolizers[binary].append_symbolizer( SystemSymbolizerFactory(self.system, addr, binary)) diff --git a/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc index 1d8b04d..200de2c 100644 --- a/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc +++ b/contrib/compiler-rt/lib/asan/tests/asan_asm_test.cc @@ -232,7 +232,7 @@ TEST(AddressSanitizer, asm_flags) { long magic = 0x1234; long r = 0x0; -#if defined(__x86_64__) +#if defined(__x86_64__) && !defined(__ILP32__) __asm__("xorq %%rax, %%rax \n\t" "movq (%[p]), %%rax \n\t" "sete %%al \n\t" @@ -248,7 +248,7 @@ TEST(AddressSanitizer, asm_flags) { : [r] "=r"(r) : [p] "r"(&magic) : "eax", "memory"); -#endif // defined(__x86_64__) +#endif // defined(__x86_64__) && !defined(__ILP32__) ASSERT_EQ(0x1, r); } diff --git a/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc index 1cd2a08..89b0d3d 100644 --- a/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc +++ b/contrib/compiler-rt/lib/asan/tests/asan_str_test.cc @@ -290,9 +290,6 @@ void RunStrCmpTest(PointerToStrCmp StrCmp) { Ident(StrCmp(s1, s2)); Ident(StrCmp(s1, s2 + size - 1)); Ident(StrCmp(s1 + size - 1, s2 + size - 1)); - s1[size - 1] = 'z'; - s2[size - 1] = 'x'; - Ident(StrCmp(s1, s2)); // One of arguments points to not allocated memory. EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1)); EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1)); @@ -371,17 +368,14 @@ TEST(AddressSanitizer, StrCatOOBTest) { // One of arguments points to not allocated memory. EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1)); EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1)); - EXPECT_DEATH(strcat(to + to_size, from), RightOOBWriteMessage(0)); EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0)); // "from" is not zero-terminated. from[from_size - 1] = 'z'; EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0)); from[from_size - 1] = '\0'; - // "to" is not zero-terminated. - memset(to, 'z', to_size); - EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0)); // "to" is too short to fit "from". + memset(to, 'z', to_size); to[to_size - from_size + 1] = '\0'; EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0)); // length of "to" is just enough. @@ -409,7 +403,6 @@ TEST(AddressSanitizer, StrNCatOOBTest) { // One of arguments points to not allocated memory. EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1)); EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1)); - EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBWriteMessage(0)); EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0)); memset(from, 'z', from_size); @@ -417,8 +410,6 @@ TEST(AddressSanitizer, StrNCatOOBTest) { to[0] = '\0'; // "from" is too short. EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0)); - // "to" is not zero-terminated. - EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBWriteMessage(0)); // "to" is too short to fit "from". to[0] = 'z'; to[to_size - from_size + 1] = '\0'; @@ -508,20 +499,15 @@ void RunAtoiOOBTest(PointerToCallAtoi Atoi) { EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1)); // Die if a buffer doesn't have terminating NULL. EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0)); - // Make last symbol a terminating NULL or other non-digit. + // Make last symbol a terminating NULL array[9] = '\0'; Atoi(array); - array[9] = 'a'; - Atoi(array); - Atoi(array + 9); // Sometimes we need to detect overflow if no digits are found. memset(array, ' ', 10); EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0)); array[9] = '-'; EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0)); EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0)); - array[8] = '-'; - Atoi(array); free(array); } @@ -546,7 +532,6 @@ typedef void(*PointerToCallStrtol)(const char*, char**, int); void RunStrtolOOBTest(PointerToCallStrtol Strtol) { char *array = MallocAndMemsetString(3); - char *endptr = NULL; array[0] = '1'; array[1] = '2'; array[2] = '3'; @@ -554,19 +539,12 @@ void RunStrtolOOBTest(PointerToCallStrtol Strtol) { EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0)); EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1)); // Buffer overflow if there is no terminating null (depends on base). - Strtol(array, &endptr, 3); - EXPECT_EQ(array + 2, endptr); EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); array[2] = 'z'; - Strtol(array, &endptr, 35); - EXPECT_EQ(array + 2, endptr); EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0)); // Add terminating zero to get rid of overflow. array[2] = '\0'; Strtol(array, NULL, 36); - // Don't check for overflow if base is invalid. - Strtol(array - 1, NULL, -1); - Strtol(array + 3, NULL, 1); // Sometimes we need to detect overflow if no digits are found. array[0] = array[1] = array[2] = ' '; EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); @@ -574,13 +552,6 @@ void RunStrtolOOBTest(PointerToCallStrtol Strtol) { EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); array[2] = '-'; EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); - array[1] = '+'; - Strtol(array, NULL, 0); - array[1] = array[2] = 'z'; - Strtol(array, &endptr, 0); - EXPECT_EQ(array, endptr); - Strtol(array + 2, NULL, 0); - EXPECT_EQ(array, endptr); free(array); } diff --git a/contrib/compiler-rt/lib/asan/tests/asan_test.cc b/contrib/compiler-rt/lib/asan/tests/asan_test.cc index 952b05e..07d59e0 100644 --- a/contrib/compiler-rt/lib/asan/tests/asan_test.cc +++ b/contrib/compiler-rt/lib/asan/tests/asan_test.cc @@ -31,13 +31,13 @@ NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);} template<typename T> NOINLINE void uaf_test(int size, int off) { - char *p = (char *)malloc_aaa(size); + void *p = malloc_aaa(size); free_aaa(p); for (int i = 1; i < 100; i++) free_aaa(malloc_aaa(i)); fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n", (long)sizeof(T), p, off); - asan_write((T*)(p + off)); + asan_write((T *)((char *)p + off)); } TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) { @@ -436,10 +436,10 @@ TEST(AddressSanitizer, WrongFreeTest) { void DoubleFree() { int *x = (int*)malloc(100 * sizeof(int)); - fprintf(stderr, "DoubleFree: x=%p\n", x); + fprintf(stderr, "DoubleFree: x=%p\n", (void *)x); free(x); free(x); - fprintf(stderr, "should have failed in the second free(%p)\n", x); + fprintf(stderr, "should have failed in the second free(%p)\n", (void *)x); abort(); } @@ -569,7 +569,7 @@ TEST(AddressSanitizer, LongJmpTest) { } #if !defined(_WIN32) // Only basic longjmp is available on Windows. -NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) { +NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) { // create three red zones for these two stack objects. int a; int b; @@ -577,10 +577,10 @@ NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) { int *A = Ident(&a); int *B = Ident(&b); *A = *B; - __builtin_longjmp((void**)buf, 1); + _longjmp(buf, 1); } -NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) { +NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) { // create three red zones for these two stack objects. int a; int b; @@ -588,10 +588,14 @@ NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) { int *A = Ident(&a); int *B = Ident(&b); *A = *B; - _longjmp(buf, 1); + siglongjmp(buf, 1); } -NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) { +#if !defined(__ANDROID__) && !defined(__arm__) && \ + !defined(__powerpc64__) && !defined(__powerpc__) && \ + !defined(__aarch64__) && !defined(__mips__) && \ + !defined(__mips64) +NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) { // create three red zones for these two stack objects. int a; int b; @@ -599,12 +603,9 @@ NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) { int *A = Ident(&a); int *B = Ident(&b); *A = *B; - siglongjmp(buf, 1); + __builtin_longjmp((void**)buf, 1); } -#if !defined(__ANDROID__) && !defined(__arm__) && \ - !defined(__powerpc64__) && !defined(__powerpc__) && \ - !defined(__aarch64__) // Does not work on Power and ARM: // https://code.google.com/p/address-sanitizer/issues/detail?id=185 TEST(AddressSanitizer, BuiltinLongJmpTest) { @@ -616,7 +617,8 @@ TEST(AddressSanitizer, BuiltinLongJmpTest) { } } #endif // !defined(__ANDROID__) && !defined(__powerpc64__) && - // !defined(__powerpc__) && !defined(__arm__) + // !defined(__powerpc__) && !defined(__arm__) && + // !defined(__mips__) && !defined(__mips64) TEST(AddressSanitizer, UnderscopeLongJmpTest) { static jmp_buf buf; @@ -1243,7 +1245,7 @@ TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) { const size_t kAllocSize = (1 << 28) - 1024; size_t total_size = 0; while (true) { - char *x = (char*)malloc(kAllocSize); + void *x = malloc(kAllocSize); memset(x, 0, kAllocSize); total_size += kAllocSize; fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x); |