diff --git a/contrib/compiler-rt/LICENSE.TXT b/contrib/compiler-rt/LICENSE.TXT index aa4115e2a790..a17dc12b272f 100644 --- a/contrib/compiler-rt/LICENSE.TXT +++ b/contrib/compiler-rt/LICENSE.TXT @@ -14,7 +14,7 @@ Full text of the relevant licenses is included below. University of Illinois/NCSA Open Source License -Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT +Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT All rights reserved. diff --git a/contrib/compiler-rt/include/sanitizer/allocator_interface.h b/contrib/compiler-rt/include/sanitizer/allocator_interface.h index ab251f89c619..5220631619fc 100644 --- a/contrib/compiler-rt/include/sanitizer/allocator_interface.h +++ b/contrib/compiler-rt/include/sanitizer/allocator_interface.h @@ -59,6 +59,23 @@ extern "C" { deallocation of "ptr". */ void __sanitizer_malloc_hook(const volatile void *ptr, size_t size); void __sanitizer_free_hook(const volatile void *ptr); + + /* Installs a pair of hooks for malloc/free. + Several (currently, 5) hook pairs may be installed, they are executed + in the order they were installed and after calling + __sanitizer_malloc_hook/__sanitizer_free_hook. + Unlike __sanitizer_malloc_hook/__sanitizer_free_hook these hooks can be + chained and do not rely on weak symbols working on the platform, but + require __sanitizer_install_malloc_and_free_hooks to be called at startup + and thus will not be called on malloc/free very early in the process. + Returns the number of hooks currently installed or 0 on failure. + Not thread-safe, should be called in the main thread before starting + other threads. + */ + int __sanitizer_install_malloc_and_free_hooks( + void (*malloc_hook)(const volatile void *, size_t), + void (*free_hook)(const volatile void *)); + #ifdef __cplusplus } // extern "C" #endif diff --git a/contrib/compiler-rt/include/sanitizer/common_interface_defs.h b/contrib/compiler-rt/include/sanitizer/common_interface_defs.h index b2a4bb7b89ee..1c90a60d72c3 100644 --- a/contrib/compiler-rt/include/sanitizer/common_interface_defs.h +++ b/contrib/compiler-rt/include/sanitizer/common_interface_defs.h @@ -41,6 +41,9 @@ extern "C" { // Tell the tools to write their reports to "path." instead of stderr. void __sanitizer_set_report_path(const char *path); + // Tell the tools to write their reports to the provided file descriptor + // (casted to void *). + void __sanitizer_set_report_fd(void *fd); // Notify the tools that the sandbox is going to be turned on. The reserved // parameter will be used in the future to hold a structure with functions @@ -128,8 +131,45 @@ extern "C" { const void *s2, size_t n, int result); void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1, const char *s2, size_t n, int result); + void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, + const char *s2, size_t n, int result); void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1, const char *s2, int result); + void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, + const char *s2, int result); + void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, + const char *s2, char *result); + void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, + const char *s2, char *result); + void __sanitizer_weak_hook_memmem(void *called_pc, + const void *s1, size_t len1, + const void *s2, size_t len2, void *result); + + // Prints stack traces for all live heap allocations ordered by total + // allocation size until `top_percent` of total live heap is shown. + // `top_percent` should be between 1 and 100. + // Experimental feature currently available only with asan on Linux/x86_64. + void __sanitizer_print_memory_profile(size_t top_percent); + + // Fiber annotation interface. + // Before switching to a different stack, one must call + // __sanitizer_start_switch_fiber with a pointer to the bottom of the + // destination stack and its size. When code starts running on the new stack, + // it must call __sanitizer_finish_switch_fiber to finalize the switch. + // The start_switch function takes a void** to store the current fake stack if + // there is one (it is needed when detect_stack_use_after_return is enabled). + // When restoring a stack, this pointer must be given to the finish_switch + // function. In most cases, this void* can be stored on the stack just before + // switching. When leaving a fiber definitely, null must be passed as first + // argument to the start_switch function so that the fake stack is destroyed. + // If you do not want support for stack use-after-return detection, you can + // always pass null to these two functions. + // Note that the fake stack mechanism is disabled during fiber switch, so if a + // signal callback runs during the switch, it will not benefit from the stack + // use-after-return detection. + void __sanitizer_start_switch_fiber(void **fake_stack_save, + const void *bottom, size_t size); + void __sanitizer_finish_switch_fiber(void *fake_stack_save); #ifdef __cplusplus } // extern "C" #endif diff --git a/contrib/compiler-rt/include/sanitizer/esan_interface.h b/contrib/compiler-rt/include/sanitizer/esan_interface.h new file mode 100644 index 000000000000..4aff8d47bbd1 --- /dev/null +++ b/contrib/compiler-rt/include/sanitizer/esan_interface.h @@ -0,0 +1,50 @@ +//===-- sanitizer/esan_interface.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Public interface header. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_ESAN_INTERFACE_H +#define SANITIZER_ESAN_INTERFACE_H + +#include + +// We declare our interface routines as weak to allow the user to avoid +// ifdefs and instead use this pattern to allow building the same sources +// with and without our runtime library: +// if (__esan_report) +// __esan_report(); +#ifdef _MSC_VER +/* selectany is as close to weak as we'll get. */ +#define COMPILER_RT_WEAK __declspec(selectany) +#elif __GNUC__ +#define COMPILER_RT_WEAK __attribute__((weak)) +#else +#define COMPILER_RT_WEAK +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// This function can be called mid-run (or at the end of a run for +// a server process that doesn't shut down normally) to request that +// data for that point in the run be reported from the tool. +void COMPILER_RT_WEAK __esan_report(); + +// This function returns the number of samples that the esan tool has collected +// to this point. This is useful for testing. +unsigned int COMPILER_RT_WEAK __esan_get_sample_count(); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // SANITIZER_ESAN_INTERFACE_H diff --git a/contrib/compiler-rt/include/sanitizer/linux_syscall_hooks.h b/contrib/compiler-rt/include/sanitizer/linux_syscall_hooks.h index 89867c15190a..09f261dd6722 100644 --- a/contrib/compiler-rt/include/sanitizer/linux_syscall_hooks.h +++ b/contrib/compiler-rt/include/sanitizer/linux_syscall_hooks.h @@ -1835,6 +1835,17 @@ __sanitizer_syscall_pre_impl_vfork() #define __sanitizer_syscall_post_vfork(res) \ __sanitizer_syscall_post_impl_vfork(res) +#define __sanitizer_syscall_pre_sigaction(signum, act, oldact) \ + __sanitizer_syscall_pre_impl_sigaction((long)signum, (long)act, (long)oldact) +#define __sanitizer_syscall_post_sigaction(res, signum, act, oldact) \ + __sanitizer_syscall_post_impl_sigaction(res, (long)signum, (long)act, \ + (long)oldact) +#define __sanitizer_syscall_pre_rt_sigaction(signum, act, oldact, sz) \ + __sanitizer_syscall_pre_impl_rt_sigaction((long)signum, (long)act, \ + (long)oldact, (long)sz) +#define __sanitizer_syscall_post_rt_sigaction(res, signum, act, oldact, sz) \ + __sanitizer_syscall_post_impl_rt_sigaction(res, (long)signum, (long)act, \ + (long)oldact, (long)sz) // And now a few syscalls we don't handle yet. #define __sanitizer_syscall_pre_afs_syscall(...) @@ -1889,7 +1900,6 @@ #define __sanitizer_syscall_pre_query_module(...) #define __sanitizer_syscall_pre_readahead(...) #define __sanitizer_syscall_pre_readdir(...) -#define __sanitizer_syscall_pre_rt_sigaction(...) #define __sanitizer_syscall_pre_rt_sigreturn(...) #define __sanitizer_syscall_pre_rt_sigsuspend(...) #define __sanitizer_syscall_pre_security(...) @@ -1903,7 +1913,6 @@ #define __sanitizer_syscall_pre_setreuid32(...) #define __sanitizer_syscall_pre_set_thread_area(...) #define __sanitizer_syscall_pre_setuid32(...) -#define __sanitizer_syscall_pre_sigaction(...) #define __sanitizer_syscall_pre_sigaltstack(...) #define __sanitizer_syscall_pre_sigreturn(...) #define __sanitizer_syscall_pre_sigsuspend(...) @@ -1971,7 +1980,6 @@ #define __sanitizer_syscall_post_query_module(res, ...) #define __sanitizer_syscall_post_readahead(res, ...) #define __sanitizer_syscall_post_readdir(res, ...) -#define __sanitizer_syscall_post_rt_sigaction(res, ...) #define __sanitizer_syscall_post_rt_sigreturn(res, ...) #define __sanitizer_syscall_post_rt_sigsuspend(res, ...) #define __sanitizer_syscall_post_security(res, ...) @@ -1985,7 +1993,6 @@ #define __sanitizer_syscall_post_setreuid32(res, ...) #define __sanitizer_syscall_post_set_thread_area(res, ...) #define __sanitizer_syscall_post_setuid32(res, ...) -#define __sanitizer_syscall_post_sigaction(res, ...) #define __sanitizer_syscall_post_sigaltstack(res, ...) #define __sanitizer_syscall_post_sigreturn(res, ...) #define __sanitizer_syscall_post_sigsuspend(res, ...) @@ -3062,7 +3069,13 @@ void __sanitizer_syscall_pre_impl_fork(); void __sanitizer_syscall_post_impl_fork(long res); void __sanitizer_syscall_pre_impl_vfork(); void __sanitizer_syscall_post_impl_vfork(long res); - +void __sanitizer_syscall_pre_impl_sigaction(long signum, long act, long oldact); +void __sanitizer_syscall_post_impl_sigaction(long res, long signum, long act, + long oldact); +void __sanitizer_syscall_pre_impl_rt_sigaction(long signum, long act, + long oldact, long sz); +void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act, + long oldact, long sz); #ifdef __cplusplus } // extern "C" #endif diff --git a/contrib/compiler-rt/lib/asan/asan_activation.cc b/contrib/compiler-rt/lib/asan/asan_activation.cc index 9df3b977ea1b..a5ace85038a6 100644 --- a/contrib/compiler-rt/lib/asan/asan_activation.cc +++ b/contrib/compiler-rt/lib/asan/asan_activation.cc @@ -47,6 +47,7 @@ static struct AsanDeactivatedFlags { FlagParser parser; RegisterActivationFlags(&parser, &f, &cf); + cf.SetDefaults(); // Copy the current activation flags. allocator_options.CopyTo(&f, &cf); cf.malloc_context_size = malloc_context_size; @@ -61,7 +62,7 @@ static struct AsanDeactivatedFlags { parser.ParseString(env); } - SetVerbosity(cf.verbosity); + InitializeCommonFlags(&cf); if (Verbosity()) ReportUnrecognizedFlags(); diff --git a/contrib/compiler-rt/lib/asan/asan_allocator.cc b/contrib/compiler-rt/lib/asan/asan_allocator.cc index 56f184a36651..6a5d227ca54c 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, 1UL << 40); + FIRST_32_SECOND_64(3UL << 30, 1ULL << 40); static const uptr kMaxThreadLocalQuarantine = FIRST_32_SECOND_64(1 << 18, 1 << 20); @@ -457,29 +457,28 @@ struct Allocator { return res; } - void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr, + // Set quarantine flag if chunk is allocated, issue ASan error report on + // available and quarantined chunks. Return true on success, false otherwise. + bool AtomicallySetQuarantineFlagIfAllocated(AsanChunk *m, void *ptr, BufferedStackTrace *stack) { u8 old_chunk_state = CHUNK_ALLOCATED; // Flip the chunk_state atomically to avoid race on double-free. - if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state, - CHUNK_QUARANTINE, memory_order_acquire)) + if (!atomic_compare_exchange_strong((atomic_uint8_t *)m, &old_chunk_state, + CHUNK_QUARANTINE, + memory_order_acquire)) { ReportInvalidFree(ptr, old_chunk_state, stack); + // It's not safe to push a chunk in quarantine on invalid free. + return false; + } CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state); + return true; } // Expects the chunk to already be marked as quarantined by using - // AtomicallySetQuarantineFlag. + // AtomicallySetQuarantineFlagIfAllocated. void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack, AllocType alloc_type) { CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); - - if (m->alloc_type != alloc_type) { - if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) { - ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type, - (AllocType)alloc_type); - } - } - CHECK_GE(m->alloc_tid, 0); if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area. CHECK_EQ(m->free_tid, kInvalidTid); @@ -516,13 +515,24 @@ struct Allocator { uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); - if (delete_size && flags()->new_delete_type_mismatch && - delete_size != m->UsedSize()) { - ReportNewDeleteSizeMismatch(p, delete_size, stack); - } + ASAN_FREE_HOOK(ptr); // Must mark the chunk as quarantined before any changes to its metadata. - AtomicallySetQuarantineFlag(m, ptr, stack); + // Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag. + if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return; + + if (m->alloc_type != alloc_type) { + if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) { + ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type, + (AllocType)alloc_type); + } + } + + if (delete_size && flags()->new_delete_type_mismatch && + delete_size != m->UsedSize()) { + ReportNewDeleteSizeMismatch(p, m->UsedSize(), delete_size, stack); + } + QuarantineChunk(m, ptr, stack, alloc_type); } @@ -655,6 +665,9 @@ static AsanAllocator &get_allocator() { bool AsanChunkView::IsValid() { return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE; } +bool AsanChunkView::IsAllocated() { + return chunk_ && chunk_->chunk_state == CHUNK_ALLOCATED; +} uptr AsanChunkView::Beg() { return chunk_->Beg(); } uptr AsanChunkView::End() { return Beg() + UsedSize(); } uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); } @@ -668,12 +681,15 @@ static StackTrace GetStackTraceFromId(u32 id) { return res; } +u32 AsanChunkView::GetAllocStackId() { return chunk_->alloc_context_id; } +u32 AsanChunkView::GetFreeStackId() { return chunk_->free_context_id; } + StackTrace AsanChunkView::GetAllocStack() { - return GetStackTraceFromId(chunk_->alloc_context_id); + return GetStackTraceFromId(GetAllocStackId()); } StackTrace AsanChunkView::GetFreeStack() { - return GetStackTraceFromId(chunk_->free_context_id); + return GetStackTraceFromId(GetFreeStackId()); } void InitializeAllocator(const AllocatorOptions &options) { @@ -754,7 +770,7 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size, return 0; } -uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) { +uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp) { if (!ptr) return 0; uptr usable_size = instance.AllocationSize(reinterpret_cast(ptr)); if (flags()->check_malloc_usable_size && (usable_size == 0)) { diff --git a/contrib/compiler-rt/lib/asan/asan_allocator.h b/contrib/compiler-rt/lib/asan/asan_allocator.h index e3d53330cd2f..2f9f7aaf8316 100644 --- a/contrib/compiler-rt/lib/asan/asan_allocator.h +++ b/contrib/compiler-rt/lib/asan/asan_allocator.h @@ -49,14 +49,17 @@ void GetAllocatorOptions(AllocatorOptions *options); class AsanChunkView { public: explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {} - bool IsValid(); // Checks if AsanChunkView points to a valid allocated - // or quarantined chunk. - uptr Beg(); // First byte of user memory. - uptr End(); // Last byte of user memory. - uptr UsedSize(); // Size requested by the user. + bool IsValid(); // Checks if AsanChunkView points to a valid allocated + // or quarantined chunk. + bool IsAllocated(); // Checks if the memory is currently allocated. + uptr Beg(); // First byte of user memory. + uptr End(); // Last byte of user memory. + uptr UsedSize(); // Size requested by the user. uptr AllocTid(); uptr FreeTid(); bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; } + u32 GetAllocStackId(); + u32 GetFreeStackId(); StackTrace GetAllocStack(); StackTrace GetFreeStack(); bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) { @@ -171,7 +174,7 @@ void *asan_pvalloc(uptr size, BufferedStackTrace *stack); int asan_posix_memalign(void **memptr, uptr alignment, uptr size, BufferedStackTrace *stack); -uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp); +uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp); uptr asan_mz_size(const void *ptr); void asan_mz_force_lock(); diff --git a/contrib/compiler-rt/lib/asan/asan_fake_stack.cc b/contrib/compiler-rt/lib/asan/asan_fake_stack.cc index 91fdf0aa1dca..16feccd0d54a 100644 --- a/contrib/compiler-rt/lib/asan/asan_fake_stack.cc +++ b/contrib/compiler-rt/lib/asan/asan_fake_stack.cc @@ -31,7 +31,7 @@ ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) { CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3. u64 *shadow = reinterpret_cast(MemToShadow(ptr)); if (class_id <= 6) { - for (uptr i = 0; i < (1U << class_id); i++) { + for (uptr i = 0; i < (((uptr)1) << class_id); i++) { shadow[i] = magic; // Make sure this does not become memset. SanitizerBreakOptimization(nullptr); @@ -121,7 +121,7 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) { uptr class_id = (ptr - beg) >> stack_size_log; uptr base = beg + (class_id << stack_size_log); CHECK_LE(base, ptr); - CHECK_LT(ptr, base + (1UL << stack_size_log)); + CHECK_LT(ptr, base + (((uptr)1) << stack_size_log)); uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id); uptr res = base + pos * BytesInSizeClass(class_id); *frame_end = res + BytesInSizeClass(class_id); diff --git a/contrib/compiler-rt/lib/asan/asan_fake_stack.h b/contrib/compiler-rt/lib/asan/asan_fake_stack.h index 3b1d9eb3b57e..74ca02df9056 100644 --- a/contrib/compiler-rt/lib/asan/asan_fake_stack.h +++ b/contrib/compiler-rt/lib/asan/asan_fake_stack.h @@ -69,12 +69,12 @@ class FakeStack { // stack_size_log is at least 15 (stack_size >= 32K). static uptr SizeRequiredForFlags(uptr stack_size_log) { - return 1UL << (stack_size_log + 1 - kMinStackFrameSizeLog); + return ((uptr)1) << (stack_size_log + 1 - kMinStackFrameSizeLog); } // Each size class occupies stack_size bytes. static uptr SizeRequiredForFrames(uptr stack_size_log) { - return (1ULL << stack_size_log) * kNumberOfSizeClasses; + return (((uptr)1) << stack_size_log) * kNumberOfSizeClasses; } // Number of bytes requires for the whole object. @@ -91,12 +91,12 @@ class FakeStack { // and so on. static uptr FlagsOffset(uptr stack_size_log, uptr class_id) { uptr t = kNumberOfSizeClasses - 1 - class_id; - const uptr all_ones = (1 << (kNumberOfSizeClasses - 1)) - 1; + const uptr all_ones = (((uptr)1) << (kNumberOfSizeClasses - 1)) - 1; return ((all_ones >> t) << t) << (stack_size_log - 15); } static uptr NumberOfFrames(uptr stack_size_log, uptr class_id) { - return 1UL << (stack_size_log - kMinStackFrameSizeLog - class_id); + return ((uptr)1) << (stack_size_log - kMinStackFrameSizeLog - class_id); } // Divide n by the numbe of frames in size class. @@ -114,7 +114,8 @@ class FakeStack { u8 *GetFrame(uptr stack_size_log, uptr class_id, uptr pos) { return reinterpret_cast(this) + kFlagsOffset + SizeRequiredForFlags(stack_size_log) + - (1 << stack_size_log) * class_id + BytesInSizeClass(class_id) * pos; + (((uptr)1) << stack_size_log) * class_id + + BytesInSizeClass(class_id) * pos; } // Allocate the fake frame. @@ -137,7 +138,7 @@ class FakeStack { // Number of bytes in a fake frame of this size class. static uptr BytesInSizeClass(uptr class_id) { - return 1UL << (class_id + kMinStackFrameSizeLog); + return ((uptr)1) << (class_id + kMinStackFrameSizeLog); } // The fake frame is guaranteed to have a right redzone. @@ -159,7 +160,7 @@ class FakeStack { static const uptr kFlagsOffset = 4096; // This is were the flags begin. // Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID COMPILER_CHECK(kNumberOfSizeClasses == 11); - static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog; + static const uptr kMaxStackMallocSize = ((uptr)1) << kMaxStackFrameSizeLog; uptr hint_position_[kNumberOfSizeClasses]; uptr stack_size_log_; diff --git a/contrib/compiler-rt/lib/asan/asan_flags.cc b/contrib/compiler-rt/lib/asan/asan_flags.cc index 363ee67e77c6..345a35ce3bb3 100644 --- a/contrib/compiler-rt/lib/asan/asan_flags.cc +++ b/contrib/compiler-rt/lib/asan/asan_flags.cc @@ -116,7 +116,7 @@ void InitializeFlags() { ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS")); #endif - SetVerbosity(common_flags()->verbosity); + InitializeCommonFlags(); // TODO(eugenis): dump all flags at verbosity>=2? if (Verbosity()) ReportUnrecognizedFlags(); @@ -159,6 +159,14 @@ void InitializeFlags() { (ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8; f->quarantine_size_mb = kDefaultQuarantineSizeMb; } + if (!f->replace_str && common_flags()->intercept_strlen) { + Report("WARNING: strlen interceptor is enabled even though replace_str=0. " + "Use intercept_strlen=0 to disable it."); + } + if (!f->replace_str && common_flags()->intercept_strchr) { + Report("WARNING: strchr* interceptors are enabled even though " + "replace_str=0. Use intercept_strchr=0 to disable them."); + } } } // namespace __asan diff --git a/contrib/compiler-rt/lib/asan/asan_flags.inc b/contrib/compiler-rt/lib/asan/asan_flags.inc index 5e69242fb8e9..9496a47490c7 100644 --- a/contrib/compiler-rt/lib/asan/asan_flags.inc +++ b/contrib/compiler-rt/lib/asan/asan_flags.inc @@ -43,7 +43,7 @@ ASAN_FLAG( "If set, uses custom wrappers and replacements for libc string functions " "to find more errors.") ASAN_FLAG(bool, replace_intrin, true, - "If set, uses custom wrappers for memset/memcpy/memmove intinsics.") + "If set, uses custom wrappers for memset/memcpy/memmove intrinsics.") ASAN_FLAG(bool, detect_stack_use_after_return, false, "Enables stack-use-after-return checking at run-time.") ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway. @@ -77,6 +77,8 @@ ASAN_FLAG(bool, print_stats, false, "Print various statistics after printing an error message or if " "atexit=1.") ASAN_FLAG(bool, print_legend, true, "Print the legend for the shadow bytes.") +ASAN_FLAG(bool, print_scariness, false, + "Print the scariness score. Experimental.") ASAN_FLAG(bool, atexit, false, "If set, prints ASan exit stats even after program terminates " "successfully.") @@ -104,7 +106,7 @@ ASAN_FLAG(bool, alloc_dealloc_mismatch, "Report errors on malloc/delete, new/free, new/delete[], etc.") ASAN_FLAG(bool, new_delete_type_mismatch, true, - "Report errors on mismatch betwen size of new and delete.") + "Report errors on mismatch between size of new and delete.") ASAN_FLAG( bool, strict_init_order, false, "If true, assume that dynamic initializers can never access globals from " @@ -135,3 +137,5 @@ ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.") ASAN_FLAG(bool, halt_on_error, true, "Crash the program after printing the first error report " "(WARNING: USE AT YOUR OWN RISK!)") +ASAN_FLAG(bool, use_odr_indicator, false, + "Use special ODR indicator symbol for ODR violation detection") diff --git a/contrib/compiler-rt/lib/asan/asan_globals.cc b/contrib/compiler-rt/lib/asan/asan_globals.cc index eb9f1bfefec2..f185761809c7 100644 --- a/contrib/compiler-rt/lib/asan/asan_globals.cc +++ b/contrib/compiler-rt/lib/asan/asan_globals.cc @@ -135,6 +135,70 @@ bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) { return false; } +enum GlobalSymbolState { + UNREGISTERED = 0, + REGISTERED = 1 +}; + +// Check ODR violation for given global G via special ODR indicator. We use +// this method in case compiler instruments global variables through their +// local aliases. +static void CheckODRViolationViaIndicator(const Global *g) { + u8 *odr_indicator = reinterpret_cast(g->odr_indicator); + if (*odr_indicator == UNREGISTERED) { + *odr_indicator = REGISTERED; + return; + } + // If *odr_indicator is DEFINED, some module have already registered + // externally visible symbol with the same name. This is an ODR violation. + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { + if (g->odr_indicator == l->g->odr_indicator && + (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && + !IsODRViolationSuppressed(g->name)) + ReportODRViolation(g, FindRegistrationSite(g), + l->g, FindRegistrationSite(l->g)); + } +} + +// Check ODR violation for given global G by checking if it's already poisoned. +// We use this method in case compiler doesn't use private aliases for global +// variables. +static void CheckODRViolationViaPoisoning(const Global *g) { + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { + // This check may not be enough: if the first global is much larger + // 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) && + !IsODRViolationSuppressed(g->name)) + ReportODRViolation(g, FindRegistrationSite(g), + l->g, FindRegistrationSite(l->g)); + } + } +} + +// Clang provides two different ways for global variables protection: +// it can poison the global itself or its private alias. In former +// case we may poison same symbol multiple times, that can help us to +// cheaply detect ODR violation: if we try to poison an already poisoned +// global, we have ODR violation error. +// In latter case, we poison each symbol exactly once, so we use special +// indicator symbol to perform similar check. +// In either case, compiler provides a special odr_indicator field to Global +// structure, that can contain two kinds of values: +// 1) Non-zero value. In this case, odr_indicator is an address of +// corresponding indicator variable for given global. +// 2) Zero. This means that we don't use private aliases for global variables +// and can freely check ODR violation with the first method. +// +// This routine chooses between two different methods of ODR violation +// detection. +static inline bool UseODRIndicator(const Global *g) { + // Use ODR indicator method iff use_odr_indicator flag is set and + // indicator symbol address is not 0. + return flags()->use_odr_indicator && g->odr_indicator > 0; +} + // Register a global variable. // This function may be called more than once for every global // so we store the globals in a map. @@ -144,22 +208,24 @@ static void RegisterGlobal(const Global *g) { ReportGlobal(*g, "Added"); CHECK(flags()->report_globals); CHECK(AddrIsInMem(g->beg)); - CHECK(AddrIsAlignedByGranularity(g->beg)); + if (!AddrIsAlignedByGranularity(g->beg)) { + Report("The following global variable is not properly aligned.\n"); + Report("This may happen if another global with the same name\n"); + Report("resides in another non-instrumented module.\n"); + Report("Or the global comes from a C file built w/o -fno-common.\n"); + Report("In either case this is likely an ODR violation bug,\n"); + Report("but AddressSanitizer can not provide more details.\n"); + ReportODRViolation(g, FindRegistrationSite(g), g, FindRegistrationSite(g)); + CHECK(AddrIsAlignedByGranularity(g->beg)); + } CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); if (flags()->detect_odr_violation) { // Try detecting ODR (One Definition Rule) violation, i.e. the situation // where two globals with the same name are defined in different modules. - if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { - // This check may not be enough: if the first global is much larger - // 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) && - !IsODRViolationSuppressed(g->name)) - ReportODRViolation(g, FindRegistrationSite(g), - l->g, FindRegistrationSite(l->g)); - } - } + if (UseODRIndicator(g)) + CheckODRViolationViaIndicator(g); + else + CheckODRViolationViaPoisoning(g); } if (CanPoisonMemory()) PoisonRedZones(*g); @@ -190,6 +256,12 @@ static void UnregisterGlobal(const Global *g) { // We unpoison the shadow memory for the global but we do not remove it from // the list because that would require O(n^2) time with the current list // implementation. It might not be worth doing anyway. + + // Release ODR indicator. + if (UseODRIndicator(g)) { + u8 *odr_indicator = reinterpret_cast(g->odr_indicator); + *odr_indicator = UNREGISTERED; + } } void StopInitOrderChecking() { @@ -212,6 +284,25 @@ void StopInitOrderChecking() { // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT + +// Apply __asan_register_globals to all globals found in the same loaded +// executable or shared library as `flag'. The flag tracks whether globals have +// already been registered or not for this image. +void __asan_register_image_globals(uptr *flag) { + if (*flag) + return; + AsanApplyToGlobals(__asan_register_globals, flag); + *flag = 1; +} + +// This mirrors __asan_register_image_globals. +void __asan_unregister_image_globals(uptr *flag) { + if (!*flag) + return; + AsanApplyToGlobals(__asan_unregister_globals, flag); + *flag = 0; +} + // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; diff --git a/contrib/compiler-rt/lib/asan/asan_init_version.h b/contrib/compiler-rt/lib/asan/asan_init_version.h index bc8a622f5bb1..f48cc19cc515 100644 --- a/contrib/compiler-rt/lib/asan/asan_init_version.h +++ b/contrib/compiler-rt/lib/asan/asan_init_version.h @@ -19,16 +19,20 @@ extern "C" { // Every time the ASan ABI changes we also change the version number in the // __asan_init function name. Objects built with incompatible ASan ABI // versions will not link with run-time. + // // Changes between ABI versions: // v1=>v2: added 'module_name' to __asan_global // v2=>v3: stack frame description (created by the compiler) - // contains the function PC as the 3-rd field (see - // DescribeAddressIfStack). - // v3=>v4: added '__asan_global_source_location' to __asan_global. + // contains the function PC as the 3rd field (see + // DescribeAddressIfStack) + // v3=>v4: added '__asan_global_source_location' to __asan_global // v4=>v5: changed the semantics and format of __asan_stack_malloc_ and - // __asan_stack_free_ functions. + // __asan_stack_free_ functions // v5=>v6: changed the name of the version check symbol - #define __asan_version_mismatch_check __asan_version_mismatch_check_v6 + // v6=>v7: added 'odr_indicator' to __asan_global + // v7=>v8: added '__asan_(un)register_image_globals' functions for dead + // stripping support on Mach-O platforms + #define __asan_version_mismatch_check __asan_version_mismatch_check_v8 } #endif // ASAN_INIT_VERSION_H diff --git a/contrib/compiler-rt/lib/asan/asan_interceptors.cc b/contrib/compiler-rt/lib/asan/asan_interceptors.cc index d9a0c71a002d..518ceebf62a5 100644 --- a/contrib/compiler-rt/lib/asan/asan_interceptors.cc +++ b/contrib/compiler-rt/lib/asan/asan_interceptors.cc @@ -21,6 +21,7 @@ #include "asan_stack.h" #include "asan_stats.h" #include "asan_suppressions.h" +#include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_libc.h" #if SANITIZER_POSIX @@ -110,7 +111,7 @@ static inline bool RangesOverlap(const char *offset1, uptr length1, } while (0) static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { -#if ASAN_INTERCEPT_STRNLEN +#if SANITIZER_INTERCEPT_STRNLEN if (REAL(strnlen)) { return REAL(strnlen)(s, maxlen); } @@ -143,6 +144,8 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) (void) ctx; \ #define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name) +#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ + ASAN_INTERCEPT_FUNC_VER(name, ver) #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ ASAN_WRITE_RANGE(ctx, ptr, size) #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ @@ -195,6 +198,10 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) } else { \ *begin = *end = 0; \ } +// Asan needs custom handling of these: +#undef SANITIZER_INTERCEPT_MEMSET +#undef SANITIZER_INTERCEPT_MEMMOVE +#undef SANITIZER_INTERCEPT_MEMCPY #include "sanitizer_common/sanitizer_common_interceptors.inc" // Syscall interceptors don't have contexts, we don't support suppressions @@ -218,6 +225,7 @@ struct ThreadStartParam { atomic_uintptr_t is_registered; }; +#if ASAN_INTERCEPT_PTHREAD_CREATE static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { ThreadStartParam *param = reinterpret_cast(arg); AsanThread *t = nullptr; @@ -228,7 +236,6 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { return t->ThreadStart(GetTid(), ¶m->is_registered); } -#if ASAN_INTERCEPT_PTHREAD_CREATE INTERCEPTOR(int, pthread_create, void *thread, void *attr, void *(*start_routine)(void*), void *arg) { EnsureMainThreadIDIsCorrect(); @@ -242,7 +249,17 @@ INTERCEPTOR(int, pthread_create, void *thread, ThreadStartParam param; atomic_store(¶m.t, 0, memory_order_relaxed); atomic_store(¶m.is_registered, 0, memory_order_relaxed); - int result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m); + int result; + { + // Ignore all allocations made by pthread_create: thread stack/TLS may be + // stored by pthread for future reuse even after thread destruction, and + // the linked list it's stored in doesn't even hold valid pointers to the + // objects, the latter are calculated by obscure pointer arithmetic. +#if CAN_SANITIZE_LEAKS + __lsan::ScopedInterceptorDisabler disabler; +#endif + result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m); + } if (result == 0) { u32 current_tid = GetCurrentTidOrInvalid(); AsanThread *t = @@ -271,7 +288,8 @@ DEFINE_REAL_PTHREAD_FUNCTIONS #if SANITIZER_ANDROID INTERCEPTOR(void*, bsd_signal, int signum, void *handler) { - if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) { + if (!IsHandledDeadlySignal(signum) || + common_flags()->allow_user_segv_handler) { return REAL(bsd_signal)(signum, handler); } return 0; @@ -279,7 +297,8 @@ INTERCEPTOR(void*, bsd_signal, int signum, void *handler) { #endif INTERCEPTOR(void*, signal, int signum, void *handler) { - if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) { + if (!IsHandledDeadlySignal(signum) || + common_flags()->allow_user_segv_handler) { return REAL(signal)(signum, handler); } return nullptr; @@ -287,7 +306,8 @@ INTERCEPTOR(void*, signal, int signum, void *handler) { INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, struct sigaction *oldact) { - if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) { + if (!IsHandledDeadlySignal(signum) || + common_flags()->allow_user_segv_handler) { return REAL(sigaction)(signum, act, oldact); } return 0; @@ -453,25 +473,6 @@ INTERCEPTOR(void*, memset, void *block, int c, uptr size) { ASAN_MEMSET_IMPL(ctx, block, c, size); } -INTERCEPTOR(char*, strchr, const char *str, int c) { - void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, strchr); - if (UNLIKELY(!asan_inited)) return internal_strchr(str, c); - // strchr is called inside create_purgeable_zone() when MallocGuardEdges=1 is - // used. - if (asan_init_is_running) { - return REAL(strchr)(str, c); - } - ENSURE_ASAN_INITED(); - char *result = REAL(strchr)(str, c); - if (flags()->replace_str) { - 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; -} - #if ASAN_INTERCEPT_INDEX # if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX INTERCEPTOR(char*, index, const char *string, int c) @@ -549,7 +550,6 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT return REAL(strcpy)(to, from); // NOLINT } -#if ASAN_INTERCEPT_STRDUP INTERCEPTOR(char*, strdup, const char *s) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); @@ -564,29 +564,28 @@ INTERCEPTOR(char*, strdup, const char *s) { REAL(memcpy)(new_mem, s, length + 1); return reinterpret_cast(new_mem); } -#endif -INTERCEPTOR(SIZE_T, strlen, const char *s) { +#if ASAN_INTERCEPT___STRDUP +INTERCEPTOR(char*, __strdup, const char *s) { void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, strlen); - if (UNLIKELY(!asan_inited)) return internal_strlen(s); - // strlen is called from malloc_default_purgeable_zone() - // in __asan::ReplaceSystemAlloc() on Mac. - if (asan_init_is_running) { - return REAL(strlen)(s); - } + ASAN_INTERCEPTOR_ENTER(ctx, strdup); + if (UNLIKELY(!asan_inited)) return internal_strdup(s); ENSURE_ASAN_INITED(); - SIZE_T length = REAL(strlen)(s); + uptr length = REAL(strlen)(s); if (flags()->replace_str) { ASAN_READ_RANGE(ctx, s, length + 1); } - return length; + GET_STACK_TRACE_MALLOC; + void *new_mem = asan_malloc(length + 1, &stack); + REAL(memcpy)(new_mem, s, length + 1); + return reinterpret_cast(new_mem); } +#endif // ASAN_INTERCEPT___STRDUP INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, wcslen); - SIZE_T length = REAL(wcslen)(s); + SIZE_T length = internal_wcslen(s); if (!asan_init_is_running) { ENSURE_ASAN_INITED(); ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t)); @@ -607,19 +606,6 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { return REAL(strncpy)(to, from, size); } -#if ASAN_INTERCEPT_STRNLEN -INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) { - void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, strnlen); - ENSURE_ASAN_INITED(); - uptr length = REAL(strnlen)(s, maxlen); - if (flags()->replace_str) { - ASAN_READ_RANGE(ctx, s, Min(length + 1, maxlen)); - } - return length; -} -#endif // ASAN_INTERCEPT_STRNLEN - INTERCEPTOR(long, strtol, const char *nptr, // NOLINT char **endptr, int base) { void *ctx; @@ -702,12 +688,12 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT } #endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL +#if ASAN_INTERCEPT___CXA_ATEXIT static void AtCxaAtexit(void *unused) { (void)unused; StopInitOrderChecking(); } -#if ASAN_INTERCEPT___CXA_ATEXIT INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, void *dso_handle) { #if SANITIZER_MAC @@ -739,25 +725,23 @@ void InitializeAsanInterceptors() { InitializeCommonInterceptors(); // Intercept mem* functions. - ASAN_INTERCEPT_FUNC(memmove); + ASAN_INTERCEPT_FUNC(memcpy); ASAN_INTERCEPT_FUNC(memset); if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { - ASAN_INTERCEPT_FUNC(memcpy); + // In asan, REAL(memmove) is not used, but it is used in msan. + ASAN_INTERCEPT_FUNC(memmove); } + CHECK(REAL(memcpy)); // Intercept str* functions. ASAN_INTERCEPT_FUNC(strcat); // NOLINT - ASAN_INTERCEPT_FUNC(strchr); ASAN_INTERCEPT_FUNC(strcpy); // NOLINT - ASAN_INTERCEPT_FUNC(strlen); ASAN_INTERCEPT_FUNC(wcslen); ASAN_INTERCEPT_FUNC(strncat); ASAN_INTERCEPT_FUNC(strncpy); -#if ASAN_INTERCEPT_STRDUP ASAN_INTERCEPT_FUNC(strdup); -#endif -#if ASAN_INTERCEPT_STRNLEN - ASAN_INTERCEPT_FUNC(strnlen); +#if ASAN_INTERCEPT___STRDUP + ASAN_INTERCEPT_FUNC(__strdup); #endif #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX ASAN_INTERCEPT_FUNC(index); diff --git a/contrib/compiler-rt/lib/asan/asan_interceptors.h b/contrib/compiler-rt/lib/asan/asan_interceptors.h index 279c5f38451f..d747c31a5d0f 100644 --- a/contrib/compiler-rt/lib/asan/asan_interceptors.h +++ b/contrib/compiler-rt/lib/asan/asan_interceptors.h @@ -23,14 +23,12 @@ #if !SANITIZER_WINDOWS # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1 # define ASAN_INTERCEPT__LONGJMP 1 -# define ASAN_INTERCEPT_STRDUP 1 # define ASAN_INTERCEPT_INDEX 1 # define ASAN_INTERCEPT_PTHREAD_CREATE 1 # define ASAN_INTERCEPT_FORK 1 #else # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0 # define ASAN_INTERCEPT__LONGJMP 0 -# define ASAN_INTERCEPT_STRDUP 0 # define ASAN_INTERCEPT_INDEX 0 # define ASAN_INTERCEPT_PTHREAD_CREATE 0 # define ASAN_INTERCEPT_FORK 0 @@ -42,12 +40,6 @@ # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0 #endif -#if !SANITIZER_MAC -# define ASAN_INTERCEPT_STRNLEN 1 -#else -# define ASAN_INTERCEPT_STRNLEN 0 -#endif - #if SANITIZER_LINUX && !SANITIZER_ANDROID # define ASAN_INTERCEPT_SWAPCONTEXT 1 #else @@ -80,6 +72,12 @@ # define ASAN_INTERCEPT___CXA_ATEXIT 0 #endif +#if SANITIZER_LINUX && !SANITIZER_ANDROID +# define ASAN_INTERCEPT___STRDUP 1 +#else +# define ASAN_INTERCEPT___STRDUP 0 +#endif + DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size) DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size) DECLARE_REAL(void*, memset, void *block, int c, uptr size) diff --git a/contrib/compiler-rt/lib/asan/asan_interface_internal.h b/contrib/compiler-rt/lib/asan/asan_interface_internal.h index 9efddcbd42b2..3cf3413dc126 100644 --- a/contrib/compiler-rt/lib/asan/asan_interface_internal.h +++ b/contrib/compiler-rt/lib/asan/asan_interface_internal.h @@ -54,8 +54,17 @@ extern "C" { uptr has_dynamic_init; // Non-zero if the global has dynamic initializer. __asan_global_source_location *location; // Source location of a global, // or NULL if it is unknown. + uptr odr_indicator; // The address of the ODR indicator symbol. }; + // These functions can be called on some platforms to find globals in the same + // loaded image as `flag' and apply __asan_(un)register_globals to them, + // filtering out redundant calls. + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_register_image_globals(uptr *flag); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_unregister_image_globals(uptr *flag); + // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. SANITIZER_INTERFACE_ATTRIBUTE diff --git a/contrib/compiler-rt/lib/asan/asan_internal.h b/contrib/compiler-rt/lib/asan/asan_internal.h index 0ef0d0eb5263..20142372e2e3 100644 --- a/contrib/compiler-rt/lib/asan/asan_internal.h +++ b/contrib/compiler-rt/lib/asan/asan_internal.h @@ -36,9 +36,9 @@ // If set, values like allocator chunk size, as well as defaults for some flags // will be changed towards less memory overhead. #ifndef ASAN_LOW_MEMORY -#if SANITIZER_WORDSIZE == 32 +# if SANITIZER_IOS || (SANITIZER_WORDSIZE == 32) # define ASAN_LOW_MEMORY 1 -#else +# else # define ASAN_LOW_MEMORY 0 # endif #endif @@ -62,6 +62,9 @@ using __sanitizer::StackTrace; void AsanInitFromRtl(); +// asan_win.cc +void InitializePlatformExceptionHandlers(); + // asan_rtl.cc void NORETURN ShowStatsAndAbort(); @@ -73,6 +76,13 @@ void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); +// Support function for __asan_(un)register_image_globals. Searches for the +// loaded image containing `needle' and then enumerates all global metadata +// structures declared in that image, applying `op' (e.g., +// __asan_(un)register_globals) to them. +typedef void (*globals_op_fptr)(__asan_global *, uptr); +void AsanApplyToGlobals(globals_op_fptr op, const void *needle); + void AsanOnDeadlySignal(int, void *siginfo, void *context); void ReadContextStack(void *context, uptr *stack, uptr *ssize); @@ -95,16 +105,24 @@ void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name); bool PlatformHasDifferentMemcpyAndMemmove(); # define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \ (PlatformHasDifferentMemcpyAndMemmove()) +#elif SANITIZER_WINDOWS64 +# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false #else # define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true #endif // SANITIZER_MAC // Add convenient macro for interface functions that may be represented as // weak hooks. -#define ASAN_MALLOC_HOOK(ptr, size) \ - if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size) -#define ASAN_FREE_HOOK(ptr) \ - if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr) +#define ASAN_MALLOC_HOOK(ptr, size) \ + do { \ + if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size); \ + RunMallocHooks(ptr, size); \ + } while (false) +#define ASAN_FREE_HOOK(ptr) \ + do { \ + if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr); \ + RunFreeHooks(ptr); \ + } while (false) #define ASAN_ON_ERROR() \ if (&__asan_on_error) __asan_on_error() @@ -112,7 +130,6 @@ extern int asan_inited; // Used to avoid infinite recursion in __asan_init(). extern bool asan_init_is_running; extern void (*death_callback)(void); - // These magic values are written to shadow for better error reporting. const int kAsanHeapLeftRedzoneMagic = 0xfa; const int kAsanHeapRightRedzoneMagic = 0xfb; diff --git a/contrib/compiler-rt/lib/asan/asan_linux.cc b/contrib/compiler-rt/lib/asan/asan_linux.cc index e26b400562df..c051573dd494 100644 --- a/contrib/compiler-rt/lib/asan/asan_linux.cc +++ b/contrib/compiler-rt/lib/asan/asan_linux.cc @@ -69,12 +69,17 @@ asan_rt_version_t __asan_rt_version; namespace __asan { void InitializePlatformInterceptors() {} +void InitializePlatformExceptionHandlers() {} void *AsanDoesNotSupportStaticLinkage() { // This will fail to link with -static. return &_DYNAMIC; // defined in link.h } +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { + UNIMPLEMENTED(); +} + #if SANITIZER_ANDROID // FIXME: should we do anything for Android? void AsanCheckDynamicRTPrereqs() {} diff --git a/contrib/compiler-rt/lib/asan/asan_mac.cc b/contrib/compiler-rt/lib/asan/asan_mac.cc index f00d98f8e5e6..525864f72d32 100644 --- a/contrib/compiler-rt/lib/asan/asan_mac.cc +++ b/contrib/compiler-rt/lib/asan/asan_mac.cc @@ -24,9 +24,11 @@ #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mac.h" +#include #include #include #include +#include #include #include #include // for free() @@ -36,9 +38,16 @@ #include #include +// from , but we don't have that file on iOS +extern "C" { + extern char ***_NSGetArgv(void); + extern char ***_NSGetEnviron(void); +} + namespace __asan { void InitializePlatformInterceptors() {} +void InitializePlatformExceptionHandlers() {} bool PlatformHasDifferentMemcpyAndMemmove() { // On OS X 10.7 memcpy() and memmove() are both resolved @@ -60,6 +69,30 @@ void AsanCheckDynamicRTPrereqs() {} // No-op. Mac does not support static linkage anyway. void AsanCheckIncompatibleRT() {} +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { + // Find the Mach-O header for the image containing the needle + Dl_info info; + int err = dladdr(needle, &info); + if (err == 0) return; + +#if __LP64__ + const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase; +#else + const struct mach_header *mh = (struct mach_header *)info.dli_fbase; +#endif + + // Look up the __asan_globals section in that image and register its globals + unsigned long size = 0; + __asan_global *globals = (__asan_global *)getsectiondata( + mh, + "__DATA", "__asan_globals", + &size); + + if (!globals) return; + if (size % sizeof(__asan_global) != 0) return; + op(globals, size / sizeof(__asan_global)); +} + void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } diff --git a/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc b/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc index d5089f9f7b36..162abd29f191 100644 --- a/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc +++ b/contrib/compiler-rt/lib/asan/asan_malloc_linux.cc @@ -26,52 +26,58 @@ // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT -static const uptr kCallocPoolSize = 1024; -static uptr calloc_memory_for_dlsym[kCallocPoolSize]; +static uptr allocated_for_dlsym; +static const uptr kDlsymAllocPoolSize = 1024; +static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; -static bool IsInCallocPool(const void *ptr) { - sptr off = (sptr)ptr - (sptr)calloc_memory_for_dlsym; - return 0 <= off && off < (sptr)kCallocPoolSize; +static bool IsInDlsymAllocPool(const void *ptr) { + uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; + return off < sizeof(alloc_memory_for_dlsym); +} + +static void *AllocateFromLocalPool(uptr size_in_bytes) { + uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize; + void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym]; + allocated_for_dlsym += size_in_words; + CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize); + return mem; } INTERCEPTOR(void, free, void *ptr) { GET_STACK_TRACE_FREE; - if (UNLIKELY(IsInCallocPool(ptr))) + if (UNLIKELY(IsInDlsymAllocPool(ptr))) return; asan_free(ptr, &stack, FROM_MALLOC); } INTERCEPTOR(void, cfree, void *ptr) { GET_STACK_TRACE_FREE; - if (UNLIKELY(IsInCallocPool(ptr))) + if (UNLIKELY(IsInDlsymAllocPool(ptr))) return; asan_free(ptr, &stack, FROM_MALLOC); } INTERCEPTOR(void*, malloc, uptr size) { + if (UNLIKELY(!asan_inited)) + // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. + return AllocateFromLocalPool(size); GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { - if (UNLIKELY(!asan_inited)) { + if (UNLIKELY(!asan_inited)) // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. - static uptr allocated; - uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize; - void *mem = (void*)&calloc_memory_for_dlsym[allocated]; - allocated += size_in_words; - CHECK(allocated < kCallocPoolSize); - return mem; - } + return AllocateFromLocalPool(nmemb * size); GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } INTERCEPTOR(void*, realloc, void *ptr, uptr size) { GET_STACK_TRACE_MALLOC; - if (UNLIKELY(IsInCallocPool(ptr))) { - uptr offset = (uptr)ptr - (uptr)calloc_memory_for_dlsym; - uptr copy_size = Min(size, kCallocPoolSize - offset); + if (UNLIKELY(IsInDlsymAllocPool(ptr))) { + uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; + uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); void *new_ptr = asan_malloc(size, &stack); internal_memcpy(new_ptr, ptr, copy_size); return new_ptr; @@ -92,7 +98,7 @@ INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) { INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC); - DTLS_on_libc_memalign(res, size * boundary); + DTLS_on_libc_memalign(res, size); return res; } diff --git a/contrib/compiler-rt/lib/asan/asan_malloc_win.cc b/contrib/compiler-rt/lib/asan/asan_malloc_win.cc index c99e31234951..4a233dfe968c 100644 --- a/contrib/compiler-rt/lib/asan/asan_malloc_win.cc +++ b/contrib/compiler-rt/lib/asan/asan_malloc_win.cc @@ -14,6 +14,8 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_WINDOWS +#define WIN32_LEAN_AND_MEAN +#include #include "asan_allocator.h" #include "asan_interceptors.h" @@ -48,6 +50,11 @@ void _free_dbg(void *ptr, int) { free(ptr); } +ALLOCATION_FUNCTION_ATTRIBUTE +void _free_base(void *ptr) { + free(ptr); +} + ALLOCATION_FUNCTION_ATTRIBUTE void cfree(void *ptr) { CHECK(!"cfree() should not be used on Windows"); @@ -59,6 +66,11 @@ void *malloc(size_t size) { return asan_malloc(size, &stack); } +ALLOCATION_FUNCTION_ATTRIBUTE +void *_malloc_base(size_t size) { + return malloc(size); +} + ALLOCATION_FUNCTION_ATTRIBUTE void *_malloc_dbg(size_t size, int, const char *, int) { return malloc(size); @@ -70,6 +82,11 @@ void *calloc(size_t nmemb, size_t size) { return asan_calloc(nmemb, size, &stack); } +ALLOCATION_FUNCTION_ATTRIBUTE +void *_calloc_base(size_t nmemb, size_t size) { + return calloc(nmemb, size); +} + ALLOCATION_FUNCTION_ATTRIBUTE void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) { return calloc(nmemb, size); @@ -92,6 +109,11 @@ void *_realloc_dbg(void *ptr, size_t size, int) { return 0; } +ALLOCATION_FUNCTION_ATTRIBUTE +void *_realloc_base(void *ptr, size_t size) { + return realloc(ptr, size); +} + ALLOCATION_FUNCTION_ATTRIBUTE void *_recalloc(void *p, size_t n, size_t elem_size) { if (!p) @@ -103,7 +125,7 @@ void *_recalloc(void *p, size_t n, size_t elem_size) { } ALLOCATION_FUNCTION_ATTRIBUTE -size_t _msize(void *ptr) { +size_t _msize(const void *ptr) { GET_CURRENT_PC_BP_SP; (void)sp; return asan_malloc_usable_size(ptr, pc, bp); @@ -139,38 +161,89 @@ int _CrtSetReportMode(int, int) { } } // extern "C" +INTERCEPTOR_WINAPI(LPVOID, HeapAlloc, HANDLE hHeap, DWORD dwFlags, + SIZE_T dwBytes) { + GET_STACK_TRACE_MALLOC; + void *p = asan_malloc(dwBytes, &stack); + // Reading MSDN suggests that the *entire* usable allocation is zeroed out. + // Otherwise it is difficult to HeapReAlloc with HEAP_ZERO_MEMORY. + // https://blogs.msdn.microsoft.com/oldnewthing/20120316-00/?p=8083 + if (dwFlags == HEAP_ZERO_MEMORY) + internal_memset(p, 0, asan_mz_size(p)); + else + CHECK(dwFlags == 0 && "unsupported heap flags"); + return p; +} + +INTERCEPTOR_WINAPI(BOOL, HeapFree, HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) { + CHECK(dwFlags == 0 && "unsupported heap flags"); + GET_STACK_TRACE_FREE; + asan_free(lpMem, &stack, FROM_MALLOC); + return true; +} + +INTERCEPTOR_WINAPI(LPVOID, HeapReAlloc, HANDLE hHeap, DWORD dwFlags, + LPVOID lpMem, SIZE_T dwBytes) { + GET_STACK_TRACE_MALLOC; + // Realloc should never reallocate in place. + if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY) + return nullptr; + CHECK(dwFlags == 0 && "unsupported heap flags"); + return asan_realloc(lpMem, dwBytes, &stack); +} + +INTERCEPTOR_WINAPI(SIZE_T, HeapSize, HANDLE hHeap, DWORD dwFlags, + LPCVOID lpMem) { + CHECK(dwFlags == 0 && "unsupported heap flags"); + GET_CURRENT_PC_BP_SP; + (void)sp; + return asan_malloc_usable_size(lpMem, pc, bp); +} + namespace __asan { + +static void TryToOverrideFunction(const char *fname, uptr new_func) { + // Failure here is not fatal. The CRT may not be present, and different CRT + // versions use different symbols. + if (!__interception::OverrideFunction(fname, new_func)) + VPrintf(2, "Failed to override function %s\n", fname); +} + void ReplaceSystemMalloc() { #if defined(ASAN_DYNAMIC) - // We don't check the result because CRT might not be used in the process. - __interception::OverrideFunction("free", (uptr)free); - __interception::OverrideFunction("malloc", (uptr)malloc); - __interception::OverrideFunction("_malloc_crt", (uptr)malloc); - __interception::OverrideFunction("calloc", (uptr)calloc); - __interception::OverrideFunction("_calloc_crt", (uptr)calloc); - __interception::OverrideFunction("realloc", (uptr)realloc); - __interception::OverrideFunction("_realloc_crt", (uptr)realloc); - __interception::OverrideFunction("_recalloc", (uptr)_recalloc); - __interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc); - __interception::OverrideFunction("_msize", (uptr)_msize); - __interception::OverrideFunction("_expand", (uptr)_expand); + TryToOverrideFunction("free", (uptr)free); + TryToOverrideFunction("_free_base", (uptr)free); + TryToOverrideFunction("malloc", (uptr)malloc); + TryToOverrideFunction("_malloc_base", (uptr)malloc); + TryToOverrideFunction("_malloc_crt", (uptr)malloc); + TryToOverrideFunction("calloc", (uptr)calloc); + TryToOverrideFunction("_calloc_base", (uptr)calloc); + TryToOverrideFunction("_calloc_crt", (uptr)calloc); + TryToOverrideFunction("realloc", (uptr)realloc); + TryToOverrideFunction("_realloc_base", (uptr)realloc); + TryToOverrideFunction("_realloc_crt", (uptr)realloc); + TryToOverrideFunction("_recalloc", (uptr)_recalloc); + TryToOverrideFunction("_recalloc_crt", (uptr)_recalloc); + TryToOverrideFunction("_msize", (uptr)_msize); + TryToOverrideFunction("_expand", (uptr)_expand); + TryToOverrideFunction("_expand_base", (uptr)_expand); - // Override different versions of 'operator new' and 'operator delete'. - // No need to override the nothrow versions as they just wrap the throw - // versions. - // FIXME: Unfortunately, MSVC miscompiles the statements that take the - // addresses of the array versions of these operators, - // see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992 - // We might want to try to work around this by [inline] assembly or compiling - // parts of the RTL with Clang. - void *(*op_new)(size_t sz) = operator new; - void (*op_delete)(void *p) = operator delete; - void *(*op_array_new)(size_t sz) = operator new[]; - void (*op_array_delete)(void *p) = operator delete[]; - __interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new); - __interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete); - __interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new); - __interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete); + // Recent versions of ucrtbase.dll appear to be built with PGO and LTCG, which + // enable cross-module inlining. This means our _malloc_base hook won't catch + // all CRT allocations. This code here patches the import table of + // ucrtbase.dll so that all attempts to use the lower-level win32 heap + // allocation API will be directed to ASan's heap. We don't currently + // intercept all calls to HeapAlloc. If we did, we would have to check on + // HeapFree whether the pointer came from ASan of from the system. +#define INTERCEPT_UCRT_FUNCTION(func) \ + if (!INTERCEPT_FUNCTION_DLLIMPORT("ucrtbase.dll", \ + "api-ms-win-core-heap-l1-1-0.dll", func)) \ + VPrintf(2, "Failed to intercept ucrtbase.dll import %s\n", #func); + INTERCEPT_UCRT_FUNCTION(HeapAlloc); + INTERCEPT_UCRT_FUNCTION(HeapFree); + INTERCEPT_UCRT_FUNCTION(HeapReAlloc); + INTERCEPT_UCRT_FUNCTION(HeapSize); +#undef INTERCEPT_UCRT_FUNCTION #endif } } // namespace __asan diff --git a/contrib/compiler-rt/lib/asan/asan_mapping.h b/contrib/compiler-rt/lib/asan/asan_mapping.h index 8fe347c8bad0..52c4f67a5d04 100644 --- a/contrib/compiler-rt/lib/asan/asan_mapping.h +++ b/contrib/compiler-rt/lib/asan/asan_mapping.h @@ -87,6 +87,20 @@ // || `[0x08000000000, 0x08fffffffff]` || lowshadow || // || `[0x00000000000, 0x07fffffffff]` || lowmem || // +// Default Linux/S390 mapping: +// || `[0x30000000, 0x7fffffff]` || HighMem || +// || `[0x26000000, 0x2fffffff]` || HighShadow || +// || `[0x24000000, 0x25ffffff]` || ShadowGap || +// || `[0x20000000, 0x23ffffff]` || LowShadow || +// || `[0x00000000, 0x1fffffff]` || LowMem || +// +// Default Linux/SystemZ mapping: +// || `[0x14000000000000, 0x1fffffffffffff]` || HighMem || +// || `[0x12800000000000, 0x13ffffffffffff]` || HighShadow || +// || `[0x12000000000000, 0x127fffffffffff]` || ShadowGap || +// || `[0x10000000000000, 0x11ffffffffffff]` || LowShadow || +// || `[0x00000000000000, 0x0fffffffffffff]` || LowMem || +// // Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000: // || `[0x500000000000, 0x7fffffffffff]` || HighMem || // || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow || @@ -115,16 +129,18 @@ static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000 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 kIosShadowOffset64 = 0x120200000; 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; static const u64 kPPC64_ShadowOffset64 = 1ULL << 41; +static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52; static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 +static const u64 kWindowsShadowOffset64 = 1ULL << 45; // 32TB #define SHADOW_SCALE kDefaultShadowScale @@ -138,28 +154,36 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # define SHADOW_OFFSET kFreeBSD_ShadowOffset32 # elif SANITIZER_WINDOWS # define SHADOW_OFFSET kWindowsShadowOffset32 -# elif SANITIZER_IOSSIM -# define SHADOW_OFFSET kIosSimShadowOffset32 # elif SANITIZER_IOS -# define SHADOW_OFFSET kIosShadowOffset32 +# if SANITIZER_IOSSIM +# define SHADOW_OFFSET kIosSimShadowOffset32 +# else +# define SHADOW_OFFSET kIosShadowOffset32 +# endif # else # define SHADOW_OFFSET kDefaultShadowOffset32 # endif #else -# if defined(__aarch64__) +# if SANITIZER_IOS +# if SANITIZER_IOSSIM +# define SHADOW_OFFSET kIosSimShadowOffset64 +# else +# define SHADOW_OFFSET kIosShadowOffset64 +# endif +# elif defined(__aarch64__) # define SHADOW_OFFSET kAArch64_ShadowOffset64 # elif defined(__powerpc64__) # define SHADOW_OFFSET kPPC64_ShadowOffset64 +# elif defined(__s390x__) +# define SHADOW_OFFSET kSystemZ_ShadowOffset64 # elif SANITIZER_FREEBSD # define SHADOW_OFFSET kFreeBSD_ShadowOffset64 # elif SANITIZER_MAC # 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 +# elif SANITIZER_WINDOWS64 +# define SHADOW_OFFSET kWindowsShadowOffset64 # else # define SHADOW_OFFSET kDefaultShort64bitShadowOffset # endif diff --git a/contrib/compiler-rt/lib/asan/asan_memory_profile.cc b/contrib/compiler-rt/lib/asan/asan_memory_profile.cc new file mode 100644 index 000000000000..ba0051634b92 --- /dev/null +++ b/contrib/compiler-rt/lib/asan/asan_memory_profile.cc @@ -0,0 +1,100 @@ +//===-- asan_memory_profile.cc.cc -----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file implements __sanitizer_print_memory_profile. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_stackdepot.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_stoptheworld.h" +#include "lsan/lsan_common.h" +#include "asan/asan_allocator.h" + +#if CAN_SANITIZE_LEAKS + +namespace __asan { + +struct AllocationSite { + u32 id; + uptr total_size; + uptr count; +}; + +class HeapProfile { + public: + HeapProfile() : allocations_(1024) {} + void Insert(u32 id, uptr size) { + total_allocated_ += size; + total_count_++; + // Linear lookup will be good enough for most cases (although not all). + for (uptr i = 0; i < allocations_.size(); i++) { + if (allocations_[i].id == id) { + allocations_[i].total_size += size; + allocations_[i].count++; + return; + } + } + allocations_.push_back({id, size, 1}); + } + + void Print(uptr top_percent) { + InternalSort(&allocations_, allocations_.size(), + [](const AllocationSite &a, const AllocationSite &b) { + return a.total_size > b.total_size; + }); + CHECK(total_allocated_); + uptr total_shown = 0; + Printf("Live Heap Allocations: %zd bytes from %zd allocations; " + "showing top %zd%%\n", total_allocated_, total_count_, top_percent); + for (uptr i = 0; i < allocations_.size(); i++) { + auto &a = allocations_[i]; + Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size, + a.total_size * 100 / total_allocated_, a.count); + StackDepotGet(a.id).Print(); + total_shown += a.total_size; + if (total_shown * 100 / total_allocated_ > top_percent) + break; + } + } + + private: + uptr total_allocated_ = 0; + uptr total_count_ = 0; + InternalMmapVector allocations_; +}; + +static void ChunkCallback(uptr chunk, void *arg) { + HeapProfile *hp = reinterpret_cast(arg); + AsanChunkView cv = FindHeapChunkByAddress(chunk); + if (!cv.IsAllocated()) return; + u32 id = cv.GetAllocStackId(); + if (!id) return; + hp->Insert(id, cv.UsedSize()); +} + +static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list, + void *argument) { + HeapProfile hp; + __lsan::ForEachChunk(ChunkCallback, &hp); + hp.Print(reinterpret_cast(argument)); +} + +} // namespace __asan + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_print_memory_profile(uptr top_percent) { + __sanitizer::StopTheWorld(__asan::MemoryProfileCB, (void*)top_percent); +} +} // extern "C" + +#endif // CAN_SANITIZE_LEAKS diff --git a/contrib/compiler-rt/lib/asan/asan_new_delete.cc b/contrib/compiler-rt/lib/asan/asan_new_delete.cc index b5ba13ef4055..fef66041f606 100644 --- a/contrib/compiler-rt/lib/asan/asan_new_delete.cc +++ b/contrib/compiler-rt/lib/asan/asan_new_delete.cc @@ -20,9 +20,25 @@ #include -// C++ operators can't have visibility attributes on Windows. +// C++ operators can't have dllexport attributes on Windows. We export them +// anyway by passing extra -export flags to the linker, which is exactly that +// dllexport would normally do. We need to export them in order to make the +// VS2015 dynamic CRT (MD) work. #if SANITIZER_WINDOWS # define CXX_OPERATOR_ATTRIBUTE +# ifdef _WIN64 +# pragma comment(linker, "/export:??2@YAPEAX_K@Z") // operator new +# pragma comment(linker, "/export:??3@YAXPEAX@Z") // operator delete +# pragma comment(linker, "/export:??3@YAXPEAX_K@Z") // sized operator delete +# pragma comment(linker, "/export:??_U@YAPEAX_K@Z") // operator new[] +# pragma comment(linker, "/export:??_V@YAXPEAX@Z") // operator delete[] +# else +# pragma comment(linker, "/export:??2@YAPAXI@Z") // operator new +# pragma comment(linker, "/export:??3@YAXPAX@Z") // operator delete +# pragma comment(linker, "/export:??3@YAXPAXI@Z") // sized operator delete +# pragma comment(linker, "/export:??_U@YAPAXI@Z") // operator new[] +# pragma comment(linker, "/export:??_V@YAXPAX@Z") // operator delete[] +# endif #else # define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE #endif diff --git a/contrib/compiler-rt/lib/asan/asan_poisoning.cc b/contrib/compiler-rt/lib/asan/asan_poisoning.cc index f77ab8780bb7..50877ae59115 100644 --- a/contrib/compiler-rt/lib/asan/asan_poisoning.cc +++ b/contrib/compiler-rt/lib/asan/asan_poisoning.cc @@ -343,7 +343,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p, &stack); } CHECK_LE(end - beg, - FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check. + FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check. uptr a = RoundDownTo(Min(old_mid, new_mid), granularity); uptr c = RoundUpTo(Max(old_mid, new_mid), granularity); diff --git a/contrib/compiler-rt/lib/asan/asan_posix.cc b/contrib/compiler-rt/lib/asan/asan_posix.cc index 9e01bcd091bf..84a29ec6a9d9 100644 --- a/contrib/compiler-rt/lib/asan/asan_posix.cc +++ b/contrib/compiler-rt/lib/asan/asan_posix.cc @@ -36,14 +36,23 @@ namespace __asan { void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); int code = (int)((siginfo_t*)siginfo)->si_code; - // Write the first message using the bullet-proof write. - if (18 != internal_write(2, "ASAN:DEADLYSIGNAL\n", 18)) Die(); + // Write the first message using fd=2, just in case. + // It may actually fail to write in case stderr is closed. + internal_write(2, "ASAN:DEADLYSIGNAL\n", 18); SignalContext sig = SignalContext::Create(siginfo, context); // Access at a reasonable offset above SP, or slightly below it (to account // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is // probably a stack overflow. +#ifdef __s390__ + // On s390, the fault address in siginfo points to start of the page, not + // to the precise word that was accessed. Mask off the low bits of sp to + // take it into account. + bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) && + sig.addr < sig.sp + 0xFFFF; +#else bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; +#endif #if __powerpc__ // Large stack frames can be allocated with e.g. diff --git a/contrib/compiler-rt/lib/asan/asan_report.cc b/contrib/compiler-rt/lib/asan/asan_report.cc index bb7e36e84652..9f2f12d51eaa 100644 --- a/contrib/compiler-rt/lib/asan/asan_report.cc +++ b/contrib/compiler-rt/lib/asan/asan_report.cc @@ -16,6 +16,7 @@ #include "asan_internal.h" #include "asan_mapping.h" #include "asan_report.h" +#include "asan_scariness_score.h" #include "asan_stack.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_common.h" @@ -470,7 +471,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) { // previously. That's unfortunate, but I have no better solution, // especially given that the alloca may be from entirely different place // (e.g. use-after-scope, or different thread's stack). -#if defined(__powerpc64__) && defined(__BIG_ENDIAN__) +#if SANITIZER_PPC64V1 // On PowerPC64 ELFv1, the address of a function actually points to a // three-doubleword data structure with the first field containing // the address of the function's code. @@ -687,6 +688,9 @@ class ScopedInErrorReport { if (flags()->print_stats) __asan_print_accumulated_stats(); + if (common_flags()->print_cmdline) + PrintCmdline(); + // Copy the message buffer so that we could start logging without holding a // lock that gets aquired during printing. InternalScopedBuffer buffer_copy(kErrorMessageBufferSize); @@ -732,10 +736,10 @@ class ScopedInErrorReport { }; StaticSpinMutex ScopedInErrorReport::lock_; -u32 ScopedInErrorReport::reporting_thread_tid_; +u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid; void ReportStackOverflow(const SignalContext &sig) { - ScopedInErrorReport in_report; + ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true); Decorator d; Printf("%s", d.Warning()); Report( @@ -744,13 +748,14 @@ void ReportStackOverflow(const SignalContext &sig) { (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp, GetCurrentTidOrInvalid()); Printf("%s", d.EndWarning()); + ScarinessScore::PrintSimple(10, "stack-overflow"); GET_STACK_TRACE_SIGNAL(sig); stack.Print(); ReportErrorSummary("stack-overflow", &stack); } void ReportDeadlySignal(const char *description, const SignalContext &sig) { - ScopedInErrorReport in_report(/*report*/nullptr, /*fatal*/true); + ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true); Decorator d; Printf("%s", d.Warning()); Report( @@ -758,10 +763,32 @@ void ReportDeadlySignal(const char *description, const SignalContext &sig) { " (pc %p bp %p sp %p T%d)\n", description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp, GetCurrentTidOrInvalid()); - if (sig.pc < GetPageSizeCached()) { - Report("Hint: pc points to the zero page.\n"); - } Printf("%s", d.EndWarning()); + ScarinessScore SS; + if (sig.pc < GetPageSizeCached()) + Report("Hint: pc points to the zero page.\n"); + if (sig.is_memory_access) { + const char *access_type = + sig.write_flag == SignalContext::WRITE + ? "WRITE" + : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); + Report("The signal is caused by a %s memory access.\n", access_type); + if (sig.addr < GetPageSizeCached()) { + Report("Hint: address points to the zero page.\n"); + SS.Scare(10, "null-deref"); + } else if (sig.addr == sig.pc) { + SS.Scare(60, "wild-jump"); + } else if (sig.write_flag == SignalContext::WRITE) { + SS.Scare(30, "wild-addr-write"); + } else if (sig.write_flag == SignalContext::READ) { + SS.Scare(20, "wild-addr-read"); + } else { + SS.Scare(25, "wild-addr"); + } + } else { + SS.Scare(10, "signal"); + } + SS.Print(); GET_STACK_TRACE_SIGNAL(sig); stack.Print(); MaybeDumpInstructionBytes(sig.pc); @@ -781,13 +808,14 @@ void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); Printf("%s", d.EndWarning()); CHECK_GT(free_stack->size, 0); + ScarinessScore::PrintSimple(42, "double-free"); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); DescribeHeapAddress(addr, 1); ReportErrorSummary("double-free", &stack); } -void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, +void ReportNewDeleteSizeMismatch(uptr addr, uptr alloc_size, uptr delete_size, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; @@ -801,8 +829,9 @@ void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, Printf("%s object passed to delete has wrong type:\n", d.EndWarning()); Printf(" size of the allocated type: %zd bytes;\n" " size of the deallocated type: %zd bytes.\n", - asan_mz_size(reinterpret_cast(addr)), delete_size); + alloc_size, delete_size); CHECK_GT(free_stack->size, 0); + ScarinessScore::PrintSimple(10, "new-delete-type-mismatch"); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); DescribeHeapAddress(addr, 1); @@ -822,6 +851,7 @@ void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) { curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); Printf("%s", d.EndWarning()); CHECK_GT(free_stack->size, 0); + ScarinessScore::PrintSimple(40, "bad-free"); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); DescribeHeapAddress(addr, 1); @@ -843,6 +873,7 @@ void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, alloc_names[alloc_type], dealloc_names[dealloc_type], addr); Printf("%s", d.EndWarning()); CHECK_GT(free_stack->size, 0); + ScarinessScore::PrintSimple(10, "alloc-dealloc-mismatch"); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); DescribeHeapAddress(addr, 1); @@ -891,6 +922,7 @@ void ReportStringFunctionMemoryRangesOverlap(const char *function, "memory ranges [%p,%p) and [%p, %p) overlap\n", \ bug_type, offset1, offset1 + length1, offset2, offset2 + length2); Printf("%s", d.EndWarning()); + ScarinessScore::PrintSimple(10, bug_type); stack->Print(); DescribeAddress((uptr)offset1, length1, bug_type); DescribeAddress((uptr)offset2, length2, bug_type); @@ -905,6 +937,7 @@ void ReportStringFunctionSizeOverflow(uptr offset, uptr size, Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size); Printf("%s", d.EndWarning()); + ScarinessScore::PrintSimple(10, bug_type); stack->Print(); DescribeAddress(offset, size, bug_type); ReportErrorSummary(bug_type, stack); @@ -979,10 +1012,10 @@ static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { uptr a2 = reinterpret_cast(p2); AsanChunkView chunk1 = FindHeapChunkByAddress(a1); AsanChunkView chunk2 = FindHeapChunkByAddress(a2); - bool valid1 = chunk1.IsValid(); - bool valid2 = chunk2.IsValid(); - if ((valid1 != valid2) || (valid1 && valid2 && !chunk1.Eq(chunk2))) { - GET_CALLER_PC_BP_SP; \ + bool valid1 = chunk1.IsAllocated(); + bool valid2 = chunk2.IsAllocated(); + if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) { + GET_CALLER_PC_BP_SP; return ReportInvalidPointerPair(pc, bp, sp, a1, a2); } } @@ -1013,10 +1046,34 @@ static bool SuppressErrorReport(uptr pc) { Die(); } +static void PrintContainerOverflowHint() { + Printf("HINT: if you don't care about these errors you may set " + "ASAN_OPTIONS=detect_container_overflow=0.\n" + "If you suspect a false positive see also: " + "https://github.com/google/sanitizers/wiki/" + "AddressSanitizerContainerOverflow.\n"); +} + +static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) { + return s[-1] > 127 && s[1] > 127; +} + void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal) { if (!fatal && SuppressErrorReport(pc)) return; ENABLE_FRAME_POINTER; + ScarinessScore SS; + + if (access_size) { + if (access_size <= 9) { + char desr[] = "?-byte"; + desr[0] = '0' + access_size; + SS.Scare(access_size + access_size / 2, desr); + } else if (access_size >= 10) { + SS.Scare(15, "multi-byte"); + } + is_write ? SS.Scare(20, "write") : SS.Scare(1, "read"); + } // Optimization experiments. // The experiments can be used to evaluate potential optimizations that remove @@ -1029,6 +1086,7 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, // Determine the error type. const char *bug_descr = "unknown-crash"; + u8 shadow_val = 0; if (AddrIsInMem(addr)) { u8 *shadow_addr = (u8*)MemToShadow(addr); // If we are accessing 16 bytes, look at the second shadow byte. @@ -1037,49 +1095,76 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, // If we are in the partial right redzone, look at the next shadow byte. if (*shadow_addr > 0 && *shadow_addr < 128) shadow_addr++; - switch (*shadow_addr) { + bool far_from_bounds = false; + shadow_val = *shadow_addr; + int bug_type_score = 0; + // For use-after-frees reads are almost as bad as writes. + int read_after_free_bonus = 0; + switch (shadow_val) { case kAsanHeapLeftRedzoneMagic: case kAsanHeapRightRedzoneMagic: case kAsanArrayCookieMagic: bug_descr = "heap-buffer-overflow"; + bug_type_score = 10; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); break; case kAsanHeapFreeMagic: bug_descr = "heap-use-after-free"; + bug_type_score = 20; + if (!is_write) read_after_free_bonus = 18; break; case kAsanStackLeftRedzoneMagic: bug_descr = "stack-buffer-underflow"; + bug_type_score = 25; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); break; case kAsanInitializationOrderMagic: bug_descr = "initialization-order-fiasco"; + bug_type_score = 1; break; case kAsanStackMidRedzoneMagic: case kAsanStackRightRedzoneMagic: case kAsanStackPartialRedzoneMagic: bug_descr = "stack-buffer-overflow"; + bug_type_score = 25; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); break; case kAsanStackAfterReturnMagic: bug_descr = "stack-use-after-return"; + bug_type_score = 30; + if (!is_write) read_after_free_bonus = 18; break; case kAsanUserPoisonedMemoryMagic: bug_descr = "use-after-poison"; + bug_type_score = 20; break; case kAsanContiguousContainerOOBMagic: bug_descr = "container-overflow"; + bug_type_score = 10; break; case kAsanStackUseAfterScopeMagic: bug_descr = "stack-use-after-scope"; + bug_type_score = 10; break; case kAsanGlobalRedzoneMagic: bug_descr = "global-buffer-overflow"; + bug_type_score = 10; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); break; case kAsanIntraObjectRedzone: bug_descr = "intra-object-overflow"; + bug_type_score = 10; break; case kAsanAllocaLeftMagic: case kAsanAllocaRightMagic: bug_descr = "dynamic-stack-buffer-overflow"; + bug_type_score = 25; + far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr); break; } + SS.Scare(bug_type_score + read_after_free_bonus, bug_descr); + if (far_from_bounds) + SS.Scare(10, "far-from-bounds"); } ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size, @@ -1102,10 +1187,13 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)), d.EndAccess()); + SS.Print(); GET_STACK_TRACE_FATAL(pc, bp); stack.Print(); DescribeAddress(addr, access_size, bug_descr); + if (shadow_val == kAsanContiguousContainerOOBMagic) + PrintContainerOverflowHint(); ReportErrorSummary(bug_descr, &stack); PrintShadowMemoryForAddress(addr); } diff --git a/contrib/compiler-rt/lib/asan/asan_report.h b/contrib/compiler-rt/lib/asan/asan_report.h index 559b8adfd51d..03f096581a1c 100644 --- a/contrib/compiler-rt/lib/asan/asan_report.h +++ b/contrib/compiler-rt/lib/asan/asan_report.h @@ -53,7 +53,7 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal); void ReportStackOverflow(const SignalContext &sig); void ReportDeadlySignal(const char *description, const SignalContext &sig); -void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, +void ReportNewDeleteSizeMismatch(uptr addr, uptr alloc_size, uptr delete_size, BufferedStackTrace *free_stack); void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack); void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack); diff --git a/contrib/compiler-rt/lib/asan/asan_rtl.cc b/contrib/compiler-rt/lib/asan/asan_rtl.cc index 7b8b5dd9be1b..4962b9ee1561 100644 --- a/contrib/compiler-rt/lib/asan/asan_rtl.cc +++ b/contrib/compiler-rt/lib/asan/asan_rtl.cc @@ -86,8 +86,8 @@ void ShowStatsAndAbort() { // Reserve memory range [beg, end]. // We need to use inclusive range because end+1 may not be representable. void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { - CHECK_EQ((beg % GetPageSizeCached()), 0); - CHECK_EQ(((end + 1) % GetPageSizeCached()), 0); + CHECK_EQ((beg % GetMmapGranularity()), 0); + CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); uptr size = end - beg + 1; DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. void *res = MmapFixedNoReserve(beg, size, name); @@ -320,26 +320,26 @@ static void InitializeHighMemEnd() { kHighMemEnd = GetMaxVirtualAddress(); // Increase kHighMemEnd to make sure it's properly // aligned together with kHighMemBeg: - kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1; + kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1; #endif // !ASAN_FIXED_MAPPING - CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0); + CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); } static void ProtectGap(uptr addr, uptr size) { if (!flags()->protect_shadow_gap) return; - void *res = MmapNoAccess(addr, size, "shadow gap"); + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); if (addr == (uptr)res) return; // A few pages at the start of the address space can not be protected. // But we really want to protect as much as possible, to prevent this memory // being returned as a result of a non-FIXED mmap(). if (addr == kZeroBaseShadowStart) { - uptr step = GetPageSizeCached(); + uptr step = GetMmapGranularity(); while (size > step && addr < kZeroBaseMaxShadowStart) { addr += step; size -= step; - void *res = MmapNoAccess(addr, size, "shadow gap"); + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); if (addr == (uptr)res) return; } @@ -415,10 +415,13 @@ static void AsanInitInternal() { AsanCheckIncompatibleRT(); AsanCheckDynamicRTPrereqs(); + AvoidCVE_2016_2143(); SetCanPoisonMemory(flags()->poison_heap); SetMallocContextSize(common_flags()->malloc_context_size); + InitializePlatformExceptionHandlers(); + InitializeHighMemEnd(); // Make sure we are not statically linked. @@ -462,6 +465,12 @@ static void AsanInitInternal() { kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; } +#elif SANITIZER_WINDOWS64 + // Disable the "mid mem" shadow layout. + if (!full_shadow_is_available) { + kMidMemBeg = 0; + kMidMemEnd = 0; + } #endif if (Verbosity()) PrintAddressSpaceLayout(); @@ -539,12 +548,12 @@ static void AsanInitInternal() { force_interface_symbols(); // no-op. SanitizerInitializeUnwinder(); -#if CAN_SANITIZE_LEAKS - __lsan::InitCommonLsan(); - if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { - Atexit(__lsan::DoLeakCheck); + if (CAN_SANITIZE_LEAKS) { + __lsan::InitCommonLsan(); + if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { + Atexit(__lsan::DoLeakCheck); + } } -#endif // CAN_SANITIZE_LEAKS #if CAN_SANITIZE_UB __ubsan::InitAsPlugin(); @@ -552,6 +561,15 @@ static void AsanInitInternal() { InitializeSuppressions(); + if (CAN_SANITIZE_LEAKS) { + // LateInitialize() calls dlsym, which can allocate an error string buffer + // in the TLS. Let's ignore the allocation to avoid reporting a leak. + __lsan::ScopedInterceptorDisabler disabler; + Symbolizer::LateInitialize(); + } else { + Symbolizer::LateInitialize(); + } + VReport(1, "AddressSanitizer Init done\n"); } diff --git a/contrib/compiler-rt/lib/asan/asan_scariness_score.h b/contrib/compiler-rt/lib/asan/asan_scariness_score.h new file mode 100644 index 000000000000..492eb561c6e2 --- /dev/null +++ b/contrib/compiler-rt/lib/asan/asan_scariness_score.h @@ -0,0 +1,67 @@ +//===-- asan_scariness_score.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Compute the level of scariness of the error message. +// Don't expect any deep science here, just a set of heuristics that suggest +// that e.g. 1-byte-read-global-buffer-overflow is less scary than +// 8-byte-write-stack-use-after-return. +// +// Every error report has one or more features, such as memory access size, +// type (read or write), type of accessed memory (e.g. free-d heap, or a global +// redzone), etc. Every such feature has an int score and a string description. +// The overall score is the sum of all feature scores and the description +// is a concatenation of feature descriptions. +// Examples: +// 17 (4-byte-read-heap-buffer-overflow) +// 65 (multi-byte-write-stack-use-after-return) +// 10 (null-deref) +// +//===----------------------------------------------------------------------===// + +#ifndef ASAN_SCARINESS_SCORE_H +#define ASAN_SCARINESS_SCORE_H + +#include "asan_flags.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libc.h" + +namespace __asan { +class ScarinessScore { + public: + ScarinessScore() { + descr[0] = 0; + } + void Scare(int add_to_score, const char *reason) { + if (descr[0]) + internal_strlcat(descr, "-", sizeof(descr)); + internal_strlcat(descr, reason, sizeof(descr)); + score += add_to_score; + }; + int GetScore() const { return score; } + const char *GetDescription() const { return descr; } + void Print() { + if (score && flags()->print_scariness) + Printf("SCARINESS: %d (%s)\n", score, descr); + } + static void PrintSimple(int score, const char *descr) { + ScarinessScore SS; + SS.Scare(score, descr); + SS.Print(); + } + + private: + int score = 0; + char descr[1024]; +}; + +} // namespace __asan + +#endif // ASAN_SCARINESS_SCORE_H diff --git a/contrib/compiler-rt/lib/asan/asan_stack.h b/contrib/compiler-rt/lib/asan/asan_stack.h index 5c5181509801..cc95e0f30a33 100644 --- a/contrib/compiler-rt/lib/asan/asan_stack.h +++ b/contrib/compiler-rt/lib/asan/asan_stack.h @@ -48,7 +48,10 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, uptr stack_top = t->stack_top(); uptr stack_bottom = t->stack_bottom(); ScopedUnwinding unwind_scope(t); - stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast); + if (!SANITIZER_MIPS || IsValidFrame(bp, stack_top, stack_bottom)) { + stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, + fast); + } } else if (!t && !fast) { /* If GetCurrentThread() has failed, try to do slow unwind anyways. */ stack->Unwind(max_depth, pc, bp, context, 0, 0, false); diff --git a/contrib/compiler-rt/lib/asan/asan_suppressions.cc b/contrib/compiler-rt/lib/asan/asan_suppressions.cc index 41887b5c88b4..62c868d25dbc 100644 --- a/contrib/compiler-rt/lib/asan/asan_suppressions.cc +++ b/contrib/compiler-rt/lib/asan/asan_suppressions.cc @@ -89,6 +89,7 @@ bool IsStackTraceSuppressed(const StackTrace *stack) { if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) { SymbolizedStack *frames = symbolizer->SymbolizePC(addr); + CHECK(frames); for (SymbolizedStack *cur = frames; cur; cur = cur->next) { const char *function_name = cur->info.function; if (!function_name) { diff --git a/contrib/compiler-rt/lib/asan/asan_thread.cc b/contrib/compiler-rt/lib/asan/asan_thread.cc index 69813546f551..d7e2cca65660 100644 --- a/contrib/compiler-rt/lib/asan/asan_thread.cc +++ b/contrib/compiler-rt/lib/asan/asan_thread.cc @@ -120,6 +120,71 @@ void AsanThread::Destroy() { DTLS_Destroy(); } +void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, + uptr size) { + if (atomic_load(&stack_switching_, memory_order_relaxed)) { + Report("ERROR: starting fiber switch while in fiber switch\n"); + Die(); + } + + next_stack_bottom_ = bottom; + next_stack_top_ = bottom + size; + atomic_store(&stack_switching_, 1, memory_order_release); + + FakeStack *current_fake_stack = fake_stack_; + if (fake_stack_save) + *fake_stack_save = fake_stack_; + fake_stack_ = nullptr; + SetTLSFakeStack(nullptr); + // if fake_stack_save is null, the fiber will die, delete the fakestack + if (!fake_stack_save && current_fake_stack) + current_fake_stack->Destroy(this->tid()); +} + +void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save) { + if (!atomic_load(&stack_switching_, memory_order_relaxed)) { + Report("ERROR: finishing a fiber switch that has not started\n"); + Die(); + } + + if (fake_stack_save) { + SetTLSFakeStack(fake_stack_save); + fake_stack_ = fake_stack_save; + } + + stack_bottom_ = next_stack_bottom_; + stack_top_ = next_stack_top_; + atomic_store(&stack_switching_, 0, memory_order_release); + next_stack_top_ = 0; + next_stack_bottom_ = 0; +} + +inline AsanThread::StackBounds AsanThread::GetStackBounds() const { + if (!atomic_load(&stack_switching_, memory_order_acquire)) + return StackBounds{stack_bottom_, stack_top_}; // NOLINT + char local; + const uptr cur_stack = (uptr)&local; + // Note: need to check next stack first, because FinishSwitchFiber + // may be in process of overwriting stack_top_/bottom_. But in such case + // we are already on the next stack. + if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_) + return StackBounds{next_stack_bottom_, next_stack_top_}; // NOLINT + return StackBounds{stack_bottom_, stack_top_}; // NOLINT +} + +uptr AsanThread::stack_top() { + return GetStackBounds().top; +} + +uptr AsanThread::stack_bottom() { + return GetStackBounds().bottom; +} + +uptr AsanThread::stack_size() { + const auto bounds = GetStackBounds(); + return bounds.top - bounds.bottom; +} + // We want to create the FakeStack lazyly on the first use, but not eralier // than the stack size is known and the procedure has to be async-signal safe. FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { @@ -150,6 +215,8 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { } void AsanThread::Init() { + next_stack_top_ = next_stack_bottom_ = 0; + atomic_store(&stack_switching_, false, memory_order_release); fake_stack_ = nullptr; // Will be initialized lazily if needed. CHECK_EQ(this->stack_size(), 0U); SetThreadStackAndTls(); @@ -195,10 +262,12 @@ thread_return_t AsanThread::ThreadStart( void AsanThread::SetThreadStackAndTls() { uptr tls_size = 0; - GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size_, &tls_begin_, - &tls_size); - stack_top_ = stack_bottom_ + stack_size_; + uptr stack_size = 0; + GetThreadStackAndTls(tid() == 0, const_cast(&stack_bottom_), + const_cast(&stack_size), &tls_begin_, &tls_size); + stack_top_ = stack_bottom_ + stack_size; tls_end_ = tls_begin_ + tls_size; + dtls_ = DTLS_Get(); int local; CHECK(AddrIsInStack((uptr)&local)); @@ -249,6 +318,11 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr, return true; } +bool AsanThread::AddrIsInStack(uptr addr) { + const auto bounds = GetStackBounds(); + return addr >= bounds.bottom && addr < bounds.top; +} + static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, void *addr) { AsanThreadContext *tctx = static_cast(tctx_base); @@ -322,8 +396,8 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, - uptr *tls_begin, uptr *tls_end, - uptr *cache_begin, uptr *cache_end) { + uptr *tls_begin, uptr *tls_end, uptr *cache_begin, + uptr *cache_end, DTLS **dtls) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); if (!t) return false; *stack_begin = t->stack_bottom(); @@ -333,6 +407,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, // ASan doesn't keep allocator caches in TLS, so these are unused. *cache_begin = 0; *cache_end = 0; + *dtls = t->dtls(); return true; } @@ -355,3 +430,29 @@ void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); } } // namespace __lsan + +// ---------------------- Interface ---------------- {{{1 +using namespace __asan; // NOLINT + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom, + uptr size) { + AsanThread *t = GetCurrentThread(); + if (!t) { + VReport(1, "__asan_start_switch_fiber called from unknown thread\n"); + return; + } + t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_finish_switch_fiber(void* fakestack) { + AsanThread *t = GetCurrentThread(); + if (!t) { + VReport(1, "__asan_finish_switch_fiber called from unknown thread\n"); + return; + } + t->FinishSwitchFiber((FakeStack*)fakestack); +} +} diff --git a/contrib/compiler-rt/lib/asan/asan_thread.h b/contrib/compiler-rt/lib/asan/asan_thread.h index ac35711f5794..92a92a2e863e 100644 --- a/contrib/compiler-rt/lib/asan/asan_thread.h +++ b/contrib/compiler-rt/lib/asan/asan_thread.h @@ -23,6 +23,10 @@ #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_thread_registry.h" +namespace __sanitizer { +struct DTLS; +} // namespace __sanitizer + namespace __asan { const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits. @@ -62,11 +66,12 @@ class AsanThread { thread_return_t ThreadStart(uptr os_id, atomic_uintptr_t *signal_thread_is_registered); - uptr stack_top() { return stack_top_; } - uptr stack_bottom() { return stack_bottom_; } - uptr stack_size() { return stack_size_; } + uptr stack_top(); + uptr stack_bottom(); + uptr stack_size(); uptr tls_begin() { return tls_begin_; } uptr tls_end() { return tls_end_; } + DTLS *dtls() { return dtls_; } u32 tid() { return context_->tid; } AsanThreadContext *context() { return context_; } void set_context(AsanThreadContext *context) { context_ = context; } @@ -78,9 +83,7 @@ class AsanThread { }; bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access); - bool AddrIsInStack(uptr addr) { - return addr >= stack_bottom_ && addr < stack_top_; - } + bool AddrIsInStack(uptr addr); void DeleteFakeStack(int tid) { if (!fake_stack_) return; @@ -90,13 +93,19 @@ class AsanThread { t->Destroy(tid); } + void StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size); + void FinishSwitchFiber(FakeStack *fake_stack_save); + bool has_fake_stack() { - return (reinterpret_cast(fake_stack_) > 1); + return !atomic_load(&stack_switching_, memory_order_relaxed) && + (reinterpret_cast(fake_stack_) > 1); } FakeStack *fake_stack() { if (!__asan_option_detect_stack_use_after_return) return nullptr; + if (atomic_load(&stack_switching_, memory_order_relaxed)) + return nullptr; if (!has_fake_stack()) return AsyncSignalSafeLazyInitFakeStack(); return fake_stack_; @@ -122,16 +131,27 @@ class AsanThread { void ClearShadowForThreadStackAndTLS(); FakeStack *AsyncSignalSafeLazyInitFakeStack(); + struct StackBounds { + uptr bottom; + uptr top; + }; + StackBounds GetStackBounds() const; + AsanThreadContext *context_; thread_callback_t start_routine_; void *arg_; + uptr stack_top_; uptr stack_bottom_; - // stack_size_ == stack_top_ - stack_bottom_; - // It needs to be set in a async-signal-safe manner. - uptr stack_size_; + // these variables are used when the thread is about to switch stack + uptr next_stack_top_; + uptr next_stack_bottom_; + // true if switching is in progress + atomic_uint8_t stack_switching_; + uptr tls_begin_; uptr tls_end_; + DTLS *dtls_; FakeStack *fake_stack_; AsanThreadLocalMallocStorage malloc_storage_; diff --git a/contrib/compiler-rt/lib/asan/asan_win.cc b/contrib/compiler-rt/lib/asan/asan_win.cc index 92bd893d10ef..2ef78cd15508 100644 --- a/contrib/compiler-rt/lib/asan/asan_win.cc +++ b/contrib/compiler-rt/lib/asan/asan_win.cc @@ -24,6 +24,7 @@ #include "asan_report.h" #include "asan_stack.h" #include "asan_thread.h" +#include "asan_mapping.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" @@ -46,11 +47,20 @@ 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() {} +// 64-bit msvc will not prepend an underscore for symbols. +#ifdef _WIN64 +#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 +#else #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 +#endif // }}} } // extern "C" @@ -61,6 +71,17 @@ INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { REAL(RaiseException)(a, b, c, d); } + +#ifdef _WIN64 + +INTERCEPTOR_WINAPI(int, __C_specific_handler, void *a, void *b, void *c, void *d) { // NOLINT + CHECK(REAL(__C_specific_handler)); + __asan_handle_no_return(); + return REAL(__C_specific_handler)(a, b, c, d); +} + +#else + INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) { CHECK(REAL(_except_handler3)); __asan_handle_no_return(); @@ -76,6 +97,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { __asan_handle_no_return(); return REAL(_except_handler4)(a, b, c, d); } +#endif static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { AsanThread *t = (AsanThread*)arg; @@ -139,8 +161,13 @@ namespace __asan { void InitializePlatformInterceptors() { ASAN_INTERCEPT_FUNC(CreateThread); ASAN_INTERCEPT_FUNC(RaiseException); + +#ifdef _WIN64 + ASAN_INTERCEPT_FUNC(__C_specific_handler); +#else ASAN_INTERCEPT_FUNC(_except_handler3); ASAN_INTERCEPT_FUNC(_except_handler4); +#endif // NtWaitForWorkViaWorkerFactory is always linked dynamically. CHECK(::__interception::OverrideFunction( @@ -149,6 +176,10 @@ void InitializePlatformInterceptors() { (uptr *)&REAL(NtWaitForWorkViaWorkerFactory))); } +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { + UNIMPLEMENTED(); +} + // ---------------------- TSD ---------------- {{{ static bool tsd_key_inited = false; @@ -194,6 +225,55 @@ void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); } +#if SANITIZER_WINDOWS64 +// Exception handler for dealing with shadow memory. +static LONG CALLBACK +ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) { + static uptr page_size = GetPageSizeCached(); + static uptr alloc_granularity = GetMmapGranularity(); + // Only handle access violations. + if (exception_pointers->ExceptionRecord->ExceptionCode != + EXCEPTION_ACCESS_VIOLATION) { + return EXCEPTION_CONTINUE_SEARCH; + } + + // Only handle access violations that land within the shadow memory. + uptr addr = + (uptr)(exception_pointers->ExceptionRecord->ExceptionInformation[1]); + + // Check valid shadow range. + if (!AddrIsInShadow(addr)) return EXCEPTION_CONTINUE_SEARCH; + + // This is an access violation while trying to read from the shadow. Commit + // the relevant page and let execution continue. + + // Determine the address of the page that is being accessed. + uptr page = RoundDownTo(addr, page_size); + + // Query the existing page. + MEMORY_BASIC_INFORMATION mem_info = {}; + if (::VirtualQuery((LPVOID)page, &mem_info, sizeof(mem_info)) == 0) + return EXCEPTION_CONTINUE_SEARCH; + + // Commit the page. + uptr result = + (uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE); + if (result != page) return EXCEPTION_CONTINUE_SEARCH; + + // The page mapping succeeded, so continue execution as usual. + return EXCEPTION_CONTINUE_EXECUTION; +} + +#endif + +void InitializePlatformExceptionHandlers() { +#if SANITIZER_WINDOWS64 + // On Win64, we map memory on demand with access violation handler. + // Install our exception handler. + CHECK(AddVectoredExceptionHandler(TRUE, &ShadowExceptionHandler)); +#endif +} + static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { @@ -242,10 +322,16 @@ int __asan_set_seh_filter() { } #if !ASAN_DYNAMIC -// Put a pointer to __asan_set_seh_filter at the end of the global list -// of C initializers, after the default EH is set by the CRT. -#pragma section(".CRT$XIZ", long, read) // NOLINT -__declspec(allocate(".CRT$XIZ")) +// The CRT runs initializers in this order: +// - C initializers, from XIA to XIZ +// - C++ initializers, from XCA to XCZ +// Prior to 2015, the CRT set the unhandled exception filter at priority XIY, +// near the end of C initialization. Starting in 2015, it was moved to the +// beginning of C++ initialization. We set our priority to XCAB to run +// immediately after the CRT runs. This way, our exception filter is called +// first and we can delegate to their filter if appropriate. +#pragma section(".CRT$XCAB", long, read) // NOLINT +__declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() = __asan_set_seh_filter; #endif // }}} 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 672cabf43ec1..f55588613066 100644 --- a/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc +++ b/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc @@ -21,6 +21,7 @@ #ifdef ASAN_DLL_THUNK #include "asan_init_version.h" #include "interception/interception.h" +#include "sanitizer_common/sanitizer_platform_interceptors.h" // ---------- Function interception helper functions and macros ----------- {{{1 extern "C" { @@ -335,6 +336,7 @@ 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) +INTERFACE_FUNCTION(__sanitizer_set_report_fd) INTERFACE_FUNCTION(__sanitizer_unaligned_load16) INTERFACE_FUNCTION(__sanitizer_unaligned_load32) INTERFACE_FUNCTION(__sanitizer_unaligned_load64) @@ -342,21 +344,28 @@ INTERFACE_FUNCTION(__sanitizer_unaligned_store16) INTERFACE_FUNCTION(__sanitizer_unaligned_store32) INTERFACE_FUNCTION(__sanitizer_unaligned_store64) INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container) +INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks) +INTERFACE_FUNCTION(__sanitizer_start_switch_fiber) +INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) // TODO(timurrrr): Add more interface functions on the as-needed basis. // ----------------- Memory allocation functions --------------------- WRAP_V_W(free) +WRAP_V_W(_free_base) WRAP_V_WW(_free_dbg) WRAP_W_W(malloc) +WRAP_W_W(_malloc_base) WRAP_W_WWWW(_malloc_dbg) WRAP_W_WW(calloc) +WRAP_W_WW(_calloc_base) WRAP_W_WWWWW(_calloc_dbg) WRAP_W_WWW(_calloc_impl) WRAP_W_WW(realloc) +WRAP_W_WW(_realloc_base) WRAP_W_WWW(_realloc_dbg) WRAP_W_WWW(_recalloc) @@ -371,6 +380,10 @@ WRAP_W_W(_expand_dbg) INTERCEPT_LIBRARY_FUNCTION(atoi); INTERCEPT_LIBRARY_FUNCTION(atol); + +#ifdef _WIN64 +INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler); +#else INTERCEPT_LIBRARY_FUNCTION(_except_handler3); // _except_handler4 checks -GS cookie which is different for each module, so we @@ -379,10 +392,13 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { __asan_handle_no_return(); return REAL(_except_handler4)(a, b, c, d); } +#endif INTERCEPT_LIBRARY_FUNCTION(frexp); INTERCEPT_LIBRARY_FUNCTION(longjmp); +#if SANITIZER_INTERCEPT_MEMCHR INTERCEPT_LIBRARY_FUNCTION(memchr); +#endif INTERCEPT_LIBRARY_FUNCTION(memcmp); INTERCEPT_LIBRARY_FUNCTION(memcpy); INTERCEPT_LIBRARY_FUNCTION(memmove); @@ -392,12 +408,14 @@ INTERCEPT_LIBRARY_FUNCTION(strchr); INTERCEPT_LIBRARY_FUNCTION(strcmp); INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT INTERCEPT_LIBRARY_FUNCTION(strcspn); +INTERCEPT_LIBRARY_FUNCTION(strdup); 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(strrchr); INTERCEPT_LIBRARY_FUNCTION(strspn); INTERCEPT_LIBRARY_FUNCTION(strstr); INTERCEPT_LIBRARY_FUNCTION(strtol); @@ -407,7 +425,9 @@ INTERCEPT_LIBRARY_FUNCTION(wcslen); // is defined. void InterceptHooks() { INTERCEPT_HOOKS(); +#ifndef _WIN64 INTERCEPT_FUNCTION(_except_handler4); +#endif } // We want to call __asan_init before C/C++ initializers/constructors are 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 73e5207bb334..1175522e7441 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 @@ -29,7 +29,7 @@ // 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$XCAB", long, read) // NOLINT #pragma section(".CRT$XTW", long, read) // NOLINT #pragma section(".CRT$XTY", long, read) // NOLINT @@ -93,7 +93,8 @@ 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. -__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter; +__declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() = + SetSEHFilter; } #endif // ASAN_DYNAMIC_RUNTIME_THUNK diff --git a/contrib/compiler-rt/lib/builtins/arm/adddf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/adddf3vfp.S index 2825ae92cd5a..f4c00a03e05f 100644 --- a/contrib/compiler-rt/lib/builtins/arm/adddf3vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/adddf3vfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__adddf3vfp) vmov r0, r1, d6 // move result back to r0/r1 pair bx lr END_COMPILERRT_FUNCTION(__adddf3vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/addsf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/addsf3vfp.S index bff5a7e0fbe8..af40c1cc92af 100644 --- a/contrib/compiler-rt/lib/builtins/arm/addsf3vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/addsf3vfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__addsf3vfp) vmov r0, s14 // move result back to r0 bx lr END_COMPILERRT_FUNCTION(__addsf3vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S index 036a6f542f79..8008f5fca262 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_cdcmp.S @@ -94,3 +94,5 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdrcmple) b __aeabi_cdcmple END_COMPILERRT_FUNCTION(__aeabi_cdrcmple) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S index 43594e5c3936..274baf7aecf2 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_cfcmp.S @@ -89,3 +89,5 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfrcmple) b __aeabi_cfcmple END_COMPILERRT_FUNCTION(__aeabi_cfrcmple) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S index 310c35b74932..43e439268d9a 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_dcmp.S @@ -38,3 +38,6 @@ DEFINE_AEABI_DCMP(lt) DEFINE_AEABI_DCMP(le) DEFINE_AEABI_DCMP(ge) DEFINE_AEABI_DCMP(gt) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_fcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_fcmp.S index 55f49a2b5af6..0a1d92a60b68 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_fcmp.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_fcmp.S @@ -38,3 +38,6 @@ DEFINE_AEABI_FCMP(lt) DEFINE_AEABI_FCMP(le) DEFINE_AEABI_FCMP(ge) DEFINE_AEABI_FCMP(gt) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S index 384add38279e..2fcad862f73a 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_idivmod.S @@ -26,3 +26,6 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) add sp, sp, #4 pop { pc } END_COMPILERRT_FUNCTION(__aeabi_idivmod) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S index ad06f1de2af4..9f161f3007f6 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_ldivmod.S @@ -29,3 +29,6 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod) add sp, sp, #16 pop {r11, pc} END_COMPILERRT_FUNCTION(__aeabi_ldivmod) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_memcmp.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_memcmp.S index fa693272fd48..33ea54848b26 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_memcmp.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_memcmp.S @@ -11,6 +11,7 @@ // void __aeabi_memcmp(void *dest, void *src, size_t n) { memcmp(dest, src, n); } + .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp) b memcmp @@ -19,4 +20,5 @@ END_COMPILERRT_FUNCTION(__aeabi_memcmp) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp8, __aeabi_memcmp) - .section .note.GNU-stack,"",%progbits +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_memcpy.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_memcpy.S index 35b8558f997c..eabfa490494c 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_memcpy.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_memcpy.S @@ -11,6 +11,7 @@ // void __aeabi_memcpy(void *dest, void *src, size_t n) { memcpy(dest, src, n); } + .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy) b memcpy @@ -19,4 +20,5 @@ END_COMPILERRT_FUNCTION(__aeabi_memcpy) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy8, __aeabi_memcpy) - .section .note.GNU-stack,"",%progbits +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_memmove.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_memmove.S index 2f9f789ab750..1bf08c0d5b75 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_memmove.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_memmove.S @@ -19,4 +19,5 @@ END_COMPILERRT_FUNCTION(__aeabi_memmove) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove8, __aeabi_memmove) - .section .note.GNU-stack,"",%progbits +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S index f2342f0772c2..48edd89705be 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_memset.S @@ -12,6 +12,7 @@ // void __aeabi_memset(void *dest, size_t n, int c) { memset(dest, c, n); } // void __aeabi_memclr(void *dest, size_t n) { __aeabi_memset(dest, n, 0); } + .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_memset) mov r3, r1 @@ -32,4 +33,5 @@ END_COMPILERRT_FUNCTION(__aeabi_memclr) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr8, __aeabi_memclr) - .section .note.GNU-stack,"",%progbits +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S index 8ea474d91c6b..e1e12d97aa00 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_uidivmod.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod) add sp, sp, #4 pop { pc } END_COMPILERRT_FUNCTION(__aeabi_uidivmod) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S b/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S index 4e1f8e2a6736..e8aaef282e90 100644 --- a/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S +++ b/contrib/compiler-rt/lib/builtins/arm/aeabi_uldivmod.S @@ -29,3 +29,6 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod) add sp, sp, #16 pop {r11, pc} END_COMPILERRT_FUNCTION(__aeabi_uldivmod) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/bswapdi2.S b/contrib/compiler-rt/lib/builtins/arm/bswapdi2.S index 86f3bba8c290..fb226cea249e 100644 --- a/contrib/compiler-rt/lib/builtins/arm/bswapdi2.S +++ b/contrib/compiler-rt/lib/builtins/arm/bswapdi2.S @@ -45,3 +45,6 @@ DEFINE_COMPILERRT_FUNCTION(__bswapdi2) mov r1, r2 // r1 = r2 = rev(r0) JMP(lr) END_COMPILERRT_FUNCTION(__bswapdi2) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/bswapsi2.S b/contrib/compiler-rt/lib/builtins/arm/bswapsi2.S index 59ba8158fd57..553c3c2e39c8 100644 --- a/contrib/compiler-rt/lib/builtins/arm/bswapsi2.S +++ b/contrib/compiler-rt/lib/builtins/arm/bswapsi2.S @@ -37,3 +37,6 @@ DEFINE_COMPILERRT_FUNCTION(__bswapsi2) #endif JMP(lr) END_COMPILERRT_FUNCTION(__bswapsi2) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/clzdi2.S b/contrib/compiler-rt/lib/builtins/arm/clzdi2.S index a55abac0469b..6068c176fd15 100644 --- a/contrib/compiler-rt/lib/builtins/arm/clzdi2.S +++ b/contrib/compiler-rt/lib/builtins/arm/clzdi2.S @@ -95,3 +95,6 @@ DEFINE_COMPILERRT_FUNCTION(__clzdi2) JMP(lr) #endif // __ARM_FEATURE_CLZ END_COMPILERRT_FUNCTION(__clzdi2) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/clzsi2.S b/contrib/compiler-rt/lib/builtins/arm/clzsi2.S index 1cd379bfb0a9..c2ba3a8cfcda 100644 --- a/contrib/compiler-rt/lib/builtins/arm/clzsi2.S +++ b/contrib/compiler-rt/lib/builtins/arm/clzsi2.S @@ -74,3 +74,6 @@ DEFINE_COMPILERRT_FUNCTION(__clzsi2) JMP(lr) #endif // __ARM_FEATURE_CLZ END_COMPILERRT_FUNCTION(__clzsi2) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/comparesf2.S b/contrib/compiler-rt/lib/builtins/arm/comparesf2.S index cf71d36e0517..52597b673f96 100644 --- a/contrib/compiler-rt/lib/builtins/arm/comparesf2.S +++ b/contrib/compiler-rt/lib/builtins/arm/comparesf2.S @@ -146,3 +146,6 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2) END_COMPILERRT_FUNCTION(__unordsf2) DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/divdf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/divdf3vfp.S index 6eebef167a2c..928f53809f12 100644 --- a/contrib/compiler-rt/lib/builtins/arm/divdf3vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/divdf3vfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__divdf3vfp) vmov r0, r1, d5 // move result back to r0/r1 pair bx lr END_COMPILERRT_FUNCTION(__divdf3vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/divmodsi4.S b/contrib/compiler-rt/lib/builtins/arm/divmodsi4.S index 646b9ab78fb6..999c310ec8a3 100644 --- a/contrib/compiler-rt/lib/builtins/arm/divmodsi4.S +++ b/contrib/compiler-rt/lib/builtins/arm/divmodsi4.S @@ -72,3 +72,6 @@ LOCAL_LABEL(divzero): CLEAR_FRAME_AND_RETURN #endif END_COMPILERRT_FUNCTION(__divmodsi4) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/divsf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/divsf3vfp.S index fdbaebc88371..a2e297f70157 100644 --- a/contrib/compiler-rt/lib/builtins/arm/divsf3vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/divsf3vfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__divsf3vfp) vmov r0, s13 // move result back to r0 bx lr END_COMPILERRT_FUNCTION(__divsf3vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/divsi3.S b/contrib/compiler-rt/lib/builtins/arm/divsi3.S index adf8f94fc7b8..7e23ba4fc237 100644 --- a/contrib/compiler-rt/lib/builtins/arm/divsi3.S +++ b/contrib/compiler-rt/lib/builtins/arm/divsi3.S @@ -63,3 +63,6 @@ ESTABLISH_FRAME CLEAR_FRAME_AND_RETURN #endif END_COMPILERRT_FUNCTION(__divsi3) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/eqdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/eqdf2vfp.S index 7f2fbc3072d4..95e6bb36334b 100644 --- a/contrib/compiler-rt/lib/builtins/arm/eqdf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/eqdf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp) movne r0, #0 bx lr END_COMPILERRT_FUNCTION(__eqdf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/eqsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/eqsf2vfp.S index a318b336ae9e..fbac139c193a 100644 --- a/contrib/compiler-rt/lib/builtins/arm/eqsf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/eqsf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp) movne r0, #0 bx lr END_COMPILERRT_FUNCTION(__eqsf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S index b998e589459e..563bf92afc36 100644 --- a/contrib/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp) vmov r0, r1, d7 // return result in r0/r1 pair bx lr END_COMPILERRT_FUNCTION(__extendsfdf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/fixdfsivfp.S b/contrib/compiler-rt/lib/builtins/arm/fixdfsivfp.S index e3bd8e05e01f..8263ff942f8c 100644 --- a/contrib/compiler-rt/lib/builtins/arm/fixdfsivfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/fixdfsivfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp) vmov r0, s15 // move s15 to result register bx lr END_COMPILERRT_FUNCTION(__fixdfsivfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/fixsfsivfp.S b/contrib/compiler-rt/lib/builtins/arm/fixsfsivfp.S index 3d0d0f56d235..c7c3b8117876 100644 --- a/contrib/compiler-rt/lib/builtins/arm/fixsfsivfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/fixsfsivfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp) vmov r0, s15 // move s15 to result register bx lr END_COMPILERRT_FUNCTION(__fixsfsivfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S b/contrib/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S index 35dda5b9b034..9cc1e628699e 100644 --- a/contrib/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S @@ -25,3 +25,6 @@ DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp) vmov r0, s15 // move s15 to result register bx lr END_COMPILERRT_FUNCTION(__fixunsdfsivfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/fixunssfsivfp.S b/contrib/compiler-rt/lib/builtins/arm/fixunssfsivfp.S index 5c3a7d926fcc..79d708229112 100644 --- a/contrib/compiler-rt/lib/builtins/arm/fixunssfsivfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/fixunssfsivfp.S @@ -25,3 +25,6 @@ DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp) vmov r0, s15 // move s15 to result register bx lr END_COMPILERRT_FUNCTION(__fixunssfsivfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/floatsidfvfp.S b/contrib/compiler-rt/lib/builtins/arm/floatsidfvfp.S index d69184914ccd..7623f26c6e6d 100644 --- a/contrib/compiler-rt/lib/builtins/arm/floatsidfvfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/floatsidfvfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp) vmov r0, r1, d7 // move d7 to result register pair r0/r1 bx lr END_COMPILERRT_FUNCTION(__floatsidfvfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/floatsisfvfp.S b/contrib/compiler-rt/lib/builtins/arm/floatsisfvfp.S index 4a0cb39d0eb0..c73dfac13eb2 100644 --- a/contrib/compiler-rt/lib/builtins/arm/floatsisfvfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/floatsisfvfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp) vmov r0, s15 // move s15 to result register bx lr END_COMPILERRT_FUNCTION(__floatsisfvfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/floatunssidfvfp.S b/contrib/compiler-rt/lib/builtins/arm/floatunssidfvfp.S index d92969ea3453..2a59fdb830b2 100644 --- a/contrib/compiler-rt/lib/builtins/arm/floatunssidfvfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/floatunssidfvfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp) vmov r0, r1, d7 // move d7 to result register pair r0/r1 bx lr END_COMPILERRT_FUNCTION(__floatunssidfvfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/floatunssisfvfp.S b/contrib/compiler-rt/lib/builtins/arm/floatunssisfvfp.S index f6aeba56ae15..c096263c1bca 100644 --- a/contrib/compiler-rt/lib/builtins/arm/floatunssisfvfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/floatunssisfvfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatunssisfvfp) vmov r0, s15 // move s15 to result register bx lr END_COMPILERRT_FUNCTION(__floatunssisfvfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/gedf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/gedf2vfp.S index 9e235270175c..72f13ef4e718 100644 --- a/contrib/compiler-rt/lib/builtins/arm/gedf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/gedf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__gedf2vfp) movlt r0, #0 bx lr END_COMPILERRT_FUNCTION(__gedf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/gesf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/gesf2vfp.S index 0ff608477882..c9ee52c9c449 100644 --- a/contrib/compiler-rt/lib/builtins/arm/gesf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/gesf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__gesf2vfp) movlt r0, #0 bx lr END_COMPILERRT_FUNCTION(__gesf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/gtdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/gtdf2vfp.S index 3dc5d5b59225..c7f277552fa6 100644 --- a/contrib/compiler-rt/lib/builtins/arm/gtdf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/gtdf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp) movle r0, #0 bx lr END_COMPILERRT_FUNCTION(__gtdf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/gtsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/gtsf2vfp.S index ddd843acf592..7d49e4564a8b 100644 --- a/contrib/compiler-rt/lib/builtins/arm/gtsf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/gtsf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp) movle r0, #0 bx lr END_COMPILERRT_FUNCTION(__gtsf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/ledf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/ledf2vfp.S index b06ff6db5a33..ca5b553f1153 100644 --- a/contrib/compiler-rt/lib/builtins/arm/ledf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/ledf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__ledf2vfp) movhi r0, #0 bx lr END_COMPILERRT_FUNCTION(__ledf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/lesf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/lesf2vfp.S index 9b33c0c53697..f25422ece8f5 100644 --- a/contrib/compiler-rt/lib/builtins/arm/lesf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/lesf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__lesf2vfp) movhi r0, #0 bx lr END_COMPILERRT_FUNCTION(__lesf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/ltdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/ltdf2vfp.S index 9f794b026a4a..6e2c0997c01b 100644 --- a/contrib/compiler-rt/lib/builtins/arm/ltdf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/ltdf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp) movpl r0, #0 bx lr END_COMPILERRT_FUNCTION(__ltdf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/ltsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/ltsf2vfp.S index ba190d9d8dc2..95febb60672a 100644 --- a/contrib/compiler-rt/lib/builtins/arm/ltsf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/ltsf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp) movpl r0, #0 bx lr END_COMPILERRT_FUNCTION(__ltsf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/modsi3.S b/contrib/compiler-rt/lib/builtins/arm/modsi3.S index 295a227d862e..1d302edc67bd 100644 --- a/contrib/compiler-rt/lib/builtins/arm/modsi3.S +++ b/contrib/compiler-rt/lib/builtins/arm/modsi3.S @@ -61,3 +61,6 @@ LOCAL_LABEL(divzero): CLEAR_FRAME_AND_RETURN #endif END_COMPILERRT_FUNCTION(__modsi3) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/muldf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/muldf3vfp.S index 636cc711ac1a..f638de1ad28a 100644 --- a/contrib/compiler-rt/lib/builtins/arm/muldf3vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/muldf3vfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__muldf3vfp) vmov r0, r1, d6 // move result back to r0/r1 pair bx lr END_COMPILERRT_FUNCTION(__muldf3vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/mulsf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/mulsf3vfp.S index 7f4008266bff..bef58d3a0c89 100644 --- a/contrib/compiler-rt/lib/builtins/arm/mulsf3vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/mulsf3vfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__mulsf3vfp) vmov r0, s13 // move result back to r0 bx lr END_COMPILERRT_FUNCTION(__mulsf3vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/nedf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/nedf2vfp.S index 7ab2f5501ce0..78cf529d665b 100644 --- a/contrib/compiler-rt/lib/builtins/arm/nedf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/nedf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__nedf2vfp) moveq r0, #0 bx lr END_COMPILERRT_FUNCTION(__nedf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/negdf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/negdf2vfp.S index 56d73c676176..01c8ba6a120f 100644 --- a/contrib/compiler-rt/lib/builtins/arm/negdf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/negdf2vfp.S @@ -21,3 +21,6 @@ DEFINE_COMPILERRT_FUNCTION(__negdf2vfp) eor r1, r1, #-2147483648 // flip sign bit on double in r0/r1 pair bx lr END_COMPILERRT_FUNCTION(__negdf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/negsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/negsf2vfp.S index a6e32e1ff89c..797abb32ead3 100644 --- a/contrib/compiler-rt/lib/builtins/arm/negsf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/negsf2vfp.S @@ -21,3 +21,6 @@ DEFINE_COMPILERRT_FUNCTION(__negsf2vfp) eor r0, r0, #-2147483648 // flip sign bit on float in r0 bx lr END_COMPILERRT_FUNCTION(__negsf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/nesf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/nesf2vfp.S index 9fe8ecdefb37..554d3e467512 100644 --- a/contrib/compiler-rt/lib/builtins/arm/nesf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/nesf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__nesf2vfp) moveq r0, #0 bx lr END_COMPILERRT_FUNCTION(__nesf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S b/contrib/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S index 0f6ea5136166..0692cf3e1b77 100644 --- a/contrib/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S +++ b/contrib/compiler-rt/lib/builtins/arm/restore_vfp_d8_d15_regs.S @@ -31,3 +31,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__restore_vfp_d8_d15_regs) bx lr // return to prolog END_COMPILERRT_FUNCTION(__restore_vfp_d8_d15_regs) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S b/contrib/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S index f1d90e75808c..544dd5467a4d 100644 --- a/contrib/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S +++ b/contrib/compiler-rt/lib/builtins/arm/save_vfp_d8_d15_regs.S @@ -31,3 +31,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__save_vfp_d8_d15_regs) bx lr // return to prolog END_COMPILERRT_FUNCTION(__save_vfp_d8_d15_regs) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/subdf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/subdf3vfp.S index 5f3c0f70dbc4..1fc7d18c3d3c 100644 --- a/contrib/compiler-rt/lib/builtins/arm/subdf3vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/subdf3vfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__subdf3vfp) vmov r0, r1, d6 // move result back to r0/r1 pair bx lr END_COMPILERRT_FUNCTION(__subdf3vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/subsf3vfp.S b/contrib/compiler-rt/lib/builtins/arm/subsf3vfp.S index d6e06df51920..11fe386cd0d1 100644 --- a/contrib/compiler-rt/lib/builtins/arm/subsf3vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/subsf3vfp.S @@ -25,3 +25,6 @@ DEFINE_COMPILERRT_FUNCTION(__subsf3vfp) vmov r0, s14 // move result back to r0 bx lr END_COMPILERRT_FUNCTION(__subsf3vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/switch16.S b/contrib/compiler-rt/lib/builtins/arm/switch16.S index 3c3a6b106124..df9e38e176ce 100644 --- a/contrib/compiler-rt/lib/builtins/arm/switch16.S +++ b/contrib/compiler-rt/lib/builtins/arm/switch16.S @@ -42,3 +42,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch16) bx ip // jump to computed label END_COMPILERRT_FUNCTION(__switch16) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/switch32.S b/contrib/compiler-rt/lib/builtins/arm/switch32.S index b38cd2b764a4..d97b5361436d 100644 --- a/contrib/compiler-rt/lib/builtins/arm/switch32.S +++ b/contrib/compiler-rt/lib/builtins/arm/switch32.S @@ -42,3 +42,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch32) bx ip // jump to computed label END_COMPILERRT_FUNCTION(__switch32) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/switch8.S b/contrib/compiler-rt/lib/builtins/arm/switch8.S index d7c20423def2..4d9e0eaff845 100644 --- a/contrib/compiler-rt/lib/builtins/arm/switch8.S +++ b/contrib/compiler-rt/lib/builtins/arm/switch8.S @@ -40,3 +40,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch8) bx ip // jump to computed label END_COMPILERRT_FUNCTION(__switch8) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/switchu8.S b/contrib/compiler-rt/lib/builtins/arm/switchu8.S index 1844f11c604e..4ffe35f0549b 100644 --- a/contrib/compiler-rt/lib/builtins/arm/switchu8.S +++ b/contrib/compiler-rt/lib/builtins/arm/switchu8.S @@ -40,3 +40,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switchu8) bx ip // jump to computed label END_COMPILERRT_FUNCTION(__switchu8) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S index 54c33e2d26b7..7877d6c46c11 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_4.S @@ -19,3 +19,5 @@ SYNC_OP_4(add_4) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S index 5724bb148ba7..1df07a342a1b 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_add_8.S @@ -22,3 +22,5 @@ SYNC_OP_8(add_8) #endif +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S index e2b77a1a87d4..720ff02279cd 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_4.S @@ -17,3 +17,6 @@ #define and_4(rD, rN, rM) and rD, rN, rM SYNC_OP_4(and_4) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S index a74163a8600b..4f7b5ca7ab29 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_and_8.S @@ -21,3 +21,6 @@ SYNC_OP_8(and_8) #endif + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S index 01e4f444c2f7..43da9c7d4067 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_4.S @@ -18,3 +18,5 @@ SYNC_OP_4(max_4) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S index 1eef2b223668..898fc6202ac8 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_max_8.S @@ -19,3 +19,6 @@ SYNC_OP_8(max_8) #endif + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S index 015626b63da5..bba31a03aace 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_4.S @@ -18,3 +18,5 @@ SYNC_OP_4(min_4) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S index ad5cce07544c..e7ccf9fb60ef 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_min_8.S @@ -19,3 +19,6 @@ SYNC_OP_8(min_8) #endif + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S index b32a314b3974..c13dd394588f 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_4.S @@ -18,3 +18,5 @@ SYNC_OP_4(nand_4) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S index a2c17c09c08f..e8107ab3a33c 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_nand_8.S @@ -22,3 +22,5 @@ SYNC_OP_8(nand_8) #endif +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S index f2e08576aaab..6726571a944f 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_4.S @@ -18,3 +18,5 @@ SYNC_OP_4(or_4) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S index 87b940bf620d..f7f162c7c3b3 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_or_8.S @@ -22,3 +22,5 @@ SYNC_OP_8(or_8) #endif +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S index 460b2bc1ed62..b9326b14cdd5 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_4.S @@ -19,3 +19,5 @@ SYNC_OP_4(sub_4) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S index a8035a276853..6ce743e5ee9f 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_sub_8.S @@ -22,3 +22,5 @@ SYNC_OP_8(sub_8) #endif +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S index c59153031931..b8d19ff35057 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_4.S @@ -18,3 +18,5 @@ SYNC_OP_4(umax_4) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S index d9b7965e52ba..34442fd77454 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umax_8.S @@ -19,3 +19,6 @@ SYNC_OP_8(umax_8) #endif + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S index 9f3896fca80e..0998e3e10f58 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_4.S @@ -18,3 +18,5 @@ SYNC_OP_4(umin_4) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S index 7bf5e235653c..558f91390512 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_umin_8.S @@ -19,3 +19,6 @@ SYNC_OP_8(umin_8) #endif + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S index 7e7c90c96277..824f49146880 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_4.S @@ -18,3 +18,5 @@ SYNC_OP_4(xor_4) +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S index ea9aa6d4b0e2..073fb9c20f25 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_fetch_and_xor_8.S @@ -22,3 +22,5 @@ SYNC_OP_8(xor_8) #endif +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/sync_synchronize.S b/contrib/compiler-rt/lib/builtins/arm/sync_synchronize.S index 178f24534c71..61d1db910f0d 100644 --- a/contrib/compiler-rt/lib/builtins/arm/sync_synchronize.S +++ b/contrib/compiler-rt/lib/builtins/arm/sync_synchronize.S @@ -33,3 +33,6 @@ END_COMPILERRT_FUNCTION(__sync_synchronize) .subsections_via_symbols #endif + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S index fa4362c45e77..04287ad27ce6 100644 --- a/contrib/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S @@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp) vmov r0, s15 // return result in r0 bx lr END_COMPILERRT_FUNCTION(__truncdfsf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/udivmodsi4.S b/contrib/compiler-rt/lib/builtins/arm/udivmodsi4.S index 85b84936c4b3..1ad8ee34bdef 100644 --- a/contrib/compiler-rt/lib/builtins/arm/udivmodsi4.S +++ b/contrib/compiler-rt/lib/builtins/arm/udivmodsi4.S @@ -182,3 +182,6 @@ LOCAL_LABEL(divby0): #endif END_COMPILERRT_FUNCTION(__udivmodsi4) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/udivsi3.S b/contrib/compiler-rt/lib/builtins/arm/udivsi3.S index 165b2b58acb4..085f8fb9e2df 100644 --- a/contrib/compiler-rt/lib/builtins/arm/udivsi3.S +++ b/contrib/compiler-rt/lib/builtins/arm/udivsi3.S @@ -168,3 +168,6 @@ LOCAL_LABEL(divby0): #endif END_COMPILERRT_FUNCTION(__udivsi3) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/umodsi3.S b/contrib/compiler-rt/lib/builtins/arm/umodsi3.S index 9e7a148ce46f..672487e81a63 100644 --- a/contrib/compiler-rt/lib/builtins/arm/umodsi3.S +++ b/contrib/compiler-rt/lib/builtins/arm/umodsi3.S @@ -159,3 +159,6 @@ LOCAL_LABEL(divby0): #endif END_COMPILERRT_FUNCTION(__umodsi3) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/unorddf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/unorddf2vfp.S index c4bea2d5eebd..022dd7a978af 100644 --- a/contrib/compiler-rt/lib/builtins/arm/unorddf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/unorddf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp) movvc r0, #0 bx lr END_COMPILERRT_FUNCTION(__unorddf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/arm/unordsf2vfp.S b/contrib/compiler-rt/lib/builtins/arm/unordsf2vfp.S index 886e96568103..5ebdd3df5505 100644 --- a/contrib/compiler-rt/lib/builtins/arm/unordsf2vfp.S +++ b/contrib/compiler-rt/lib/builtins/arm/unordsf2vfp.S @@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp) movvc r0, #0 bx lr END_COMPILERRT_FUNCTION(__unordsf2vfp) + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/assembly.h b/contrib/compiler-rt/lib/builtins/assembly.h index c28970534cc4..5fc74f68f603 100644 --- a/contrib/compiler-rt/lib/builtins/assembly.h +++ b/contrib/compiler-rt/lib/builtins/assembly.h @@ -30,6 +30,8 @@ #define SYMBOL_IS_FUNC(name) #define CONST_SECTION .const +#define NO_EXEC_STACK_DIRECTIVE + #elif defined(__ELF__) #define HIDDEN(name) .hidden name @@ -42,6 +44,12 @@ #endif #define CONST_SECTION .section .rodata +#if defined(__GNU__) || defined(__ANDROID__) || defined(__FreeBSD__) +#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits +#else +#define NO_EXEC_STACK_DIRECTIVE +#endif + #else // !__APPLE__ && !__ELF__ #define HIDDEN(name) @@ -54,6 +62,8 @@ .endef #define CONST_SECTION .section .rdata,"rd" +#define NO_EXEC_STACK_DIRECTIVE + #endif #if defined(__arm__) diff --git a/contrib/compiler-rt/lib/builtins/clear_cache.c b/contrib/compiler-rt/lib/builtins/clear_cache.c index bc21a1607335..2b9c1774429a 100644 --- a/contrib/compiler-rt/lib/builtins/clear_cache.c +++ b/contrib/compiler-rt/lib/builtins/clear_cache.c @@ -14,6 +14,15 @@ #if __APPLE__ #include #endif + +#if defined(_WIN32) +/* Forward declare Win32 APIs since the GCC mode driver does not handle the + newer SDKs as well as needed. */ +uint32_t FlushInstructionCache(uintptr_t hProcess, void *lpBaseAddress, + uintptr_t dwSize); +uintptr_t GetCurrentProcess(void); +#endif + #if (defined(__FreeBSD__) || defined(__Bitrig__)) && defined(__arm__) #include #include @@ -73,7 +82,7 @@ #endif #endif -#if defined(__ANDROID__) && defined(__arm__) +#if defined(__linux__) && defined(__arm__) #include #endif @@ -98,16 +107,18 @@ void __clear_cache(void *start, void *end) { arg.len = (uintptr_t)end - (uintptr_t)start; sysarch(ARM_SYNC_ICACHE, &arg); - #elif defined(__ANDROID__) + #elif defined(__linux__) register int start_reg __asm("r0") = (int) (intptr_t) start; const register int end_reg __asm("r1") = (int) (intptr_t) end; - const register int flags __asm("r2") = 0; const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush; - __asm __volatile("svc 0x0" : "=r"(start_reg) - : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), "r"(flags) : "r0"); + __asm __volatile("svc 0x0" + : "=r"(start_reg) + : "r"(syscall_nr), "r"(start_reg), "r"(end_reg)); if (start_reg != 0) { compilerrt_abort(); } + #elif defined(_WIN32) + FlushInstructionCache(GetCurrentProcess(), start, end - start); #else compilerrt_abort(); #endif diff --git a/contrib/compiler-rt/lib/builtins/cpu_model.c b/contrib/compiler-rt/lib/builtins/cpu_model.c new file mode 100644 index 000000000000..9a3737020a4e --- /dev/null +++ b/contrib/compiler-rt/lib/builtins/cpu_model.c @@ -0,0 +1,797 @@ +//===-- cpu_model.c - Support for __cpu_model builtin ------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is based on LLVM's lib/Support/Host.cpp. +// It implements the operating system Host concept and builtin +// __cpu_model for the compiler_rt library, for x86 only. +// +//===----------------------------------------------------------------------===// + +#if (defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64__) || defined(_M_X64)) && \ + (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)) + +#include + +#define bool int +#define true 1 +#define false 0 + +#ifdef _MSC_VER +#include +#endif + +enum VendorSignatures { + SIG_INTEL = 0x756e6547 /* Genu */, + SIG_AMD = 0x68747541 /* Auth */ +}; + +enum ProcessorVendors { + VENDOR_INTEL = 1, + VENDOR_AMD, + VENDOR_OTHER, + VENDOR_MAX +}; + +enum ProcessorTypes { + INTEL_ATOM = 1, + INTEL_CORE2, + INTEL_COREI7, + AMDFAM10H, + AMDFAM15H, + INTEL_i386, + INTEL_i486, + INTEL_PENTIUM, + INTEL_PENTIUM_PRO, + INTEL_PENTIUM_II, + INTEL_PENTIUM_III, + INTEL_PENTIUM_IV, + INTEL_PENTIUM_M, + INTEL_CORE_DUO, + INTEL_XEONPHI, + INTEL_X86_64, + INTEL_NOCONA, + INTEL_PRESCOTT, + AMD_i486, + AMDPENTIUM, + AMDATHLON, + AMDFAM14H, + AMDFAM16H, + CPU_TYPE_MAX +}; + +enum ProcessorSubtypes { + INTEL_COREI7_NEHALEM = 1, + INTEL_COREI7_WESTMERE, + INTEL_COREI7_SANDYBRIDGE, + AMDFAM10H_BARCELONA, + AMDFAM10H_SHANGHAI, + AMDFAM10H_ISTANBUL, + AMDFAM15H_BDVER1, + AMDFAM15H_BDVER2, + INTEL_PENTIUM_MMX, + INTEL_CORE2_65, + INTEL_CORE2_45, + INTEL_COREI7_IVYBRIDGE, + INTEL_COREI7_HASWELL, + INTEL_COREI7_BROADWELL, + INTEL_COREI7_SKYLAKE, + INTEL_COREI7_SKYLAKE_AVX512, + INTEL_ATOM_BONNELL, + INTEL_ATOM_SILVERMONT, + INTEL_KNIGHTS_LANDING, + AMDPENTIUM_K6, + AMDPENTIUM_K62, + AMDPENTIUM_K63, + AMDPENTIUM_GEODE, + AMDATHLON_TBIRD, + AMDATHLON_MP, + AMDATHLON_XP, + AMDATHLON_K8SSE3, + AMDATHLON_OPTERON, + AMDATHLON_FX, + AMDATHLON_64, + AMD_BTVER1, + AMD_BTVER2, + AMDFAM15H_BDVER3, + AMDFAM15H_BDVER4, + CPU_SUBTYPE_MAX +}; + +enum ProcessorFeatures { + FEATURE_CMOV = 0, + FEATURE_MMX, + FEATURE_POPCNT, + FEATURE_SSE, + FEATURE_SSE2, + FEATURE_SSE3, + FEATURE_SSSE3, + FEATURE_SSE4_1, + FEATURE_SSE4_2, + FEATURE_AVX, + FEATURE_AVX2, + FEATURE_AVX512, + FEATURE_AVX512SAVE, + FEATURE_MOVBE, + FEATURE_ADX, + FEATURE_EM64T +}; + +// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). +// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID +// support. Consequently, for i386, the presence of CPUID is checked first +// via the corresponding eflags bit. +static bool isCpuIdSupported() { +#if defined(__GNUC__) || defined(__clang__) +#if defined(__i386__) + int __cpuid_supported; + __asm__(" pushfl\n" + " popl %%eax\n" + " movl %%eax,%%ecx\n" + " xorl $0x00200000,%%eax\n" + " pushl %%eax\n" + " popfl\n" + " pushfl\n" + " popl %%eax\n" + " movl $0,%0\n" + " cmpl %%eax,%%ecx\n" + " je 1f\n" + " movl $1,%0\n" + "1:" + : "=r"(__cpuid_supported) + : + : "eax", "ecx"); + if (!__cpuid_supported) + return false; +#endif + return true; +#endif + return true; +} + +// This code is copied from lib/Support/Host.cpp. +// Changes to either file should be mirrored in the other. + +/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in +/// the specified arguments. If we can't run cpuid on the host, return true. +static void getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, + unsigned *rECX, unsigned *rEDX) { +#if defined(__GNUC__) || defined(__clang__) +#if defined(__x86_64__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + __asm__("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value)); +#elif defined(__i386__) + __asm__("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value)); +// pedantic #else returns to appease -Wunreachable-code (so we don't generate +// postprocessed code that looks like "return true; return false;") +#else + assert(0 && "This method is defined only for x86."); +#endif +#elif defined(_MSC_VER) + // The MSVC intrinsic is portable across x86 and x64. + int registers[4]; + __cpuid(registers, value); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; +#else + assert(0 && "This method is defined only for GNUC, Clang or MSVC."); +#endif +} + +/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return +/// the 4 values in the specified arguments. If we can't run cpuid on the host, +/// return true. +static void getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, + unsigned *rEAX, unsigned *rEBX, unsigned *rECX, + unsigned *rEDX) { +#if defined(__x86_64__) || defined(_M_X64) +#if defined(__GNUC__) || defined(__clang__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. + // FIXME: should we save this for Clang? + __asm__("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value), "c"(subleaf)); +#elif defined(_MSC_VER) + int registers[4]; + __cpuidex(registers, value, subleaf); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; +#else + assert(0 && "This method is defined only for GNUC, Clang or MSVC."); +#endif +#elif defined(__i386__) || defined(_M_IX86) +#if defined(__GNUC__) || defined(__clang__) + __asm__("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) + : "a"(value), "c"(subleaf)); +#elif defined(_MSC_VER) + __asm { + mov eax,value + mov ecx,subleaf + cpuid + mov esi,rEAX + mov dword ptr [esi],eax + mov esi,rEBX + mov dword ptr [esi],ebx + mov esi,rECX + mov dword ptr [esi],ecx + mov esi,rEDX + mov dword ptr [esi],edx + } +#else + assert(0 && "This method is defined only for GNUC, Clang or MSVC."); +#endif +#else + assert(0 && "This method is defined only for x86."); +#endif +} + +// Read control register 0 (XCR0). Used to detect features such as AVX. +static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { +#if defined(__GNUC__) || defined(__clang__) + // Check xgetbv; this uses a .byte sequence instead of the instruction + // directly because older assemblers do not include support for xgetbv and + // there is no easy way to conditionally compile based on the assembler used. + __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); + return false; +#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) + unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); + *rEAX = Result; + *rEDX = Result >> 32; + return false; +#else + return true; +#endif +} + +static void detectX86FamilyModel(unsigned EAX, unsigned *Family, + unsigned *Model) { + *Family = (EAX >> 8) & 0xf; // Bits 8 - 11 + *Model = (EAX >> 4) & 0xf; // Bits 4 - 7 + if (*Family == 6 || *Family == 0xf) { + if (*Family == 0xf) + // Examine extended family ID if family ID is F. + *Family += (EAX >> 20) & 0xff; // Bits 20 - 27 + // Examine extended model ID if family ID is 6 or F. + *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 + } +} + +static void getIntelProcessorTypeAndSubtype(unsigned int Family, + unsigned int Model, + unsigned int Brand_id, + unsigned int Features, + unsigned *Type, unsigned *Subtype) { + if (Brand_id != 0) + return; + switch (Family) { + case 3: + *Type = INTEL_i386; + break; + case 4: + switch (Model) { + case 0: // Intel486 DX processors + case 1: // Intel486 DX processors + case 2: // Intel486 SX processors + case 3: // Intel487 processors, IntelDX2 OverDrive processors, + // IntelDX2 processors + case 4: // Intel486 SL processor + case 5: // IntelSX2 processors + case 7: // Write-Back Enhanced IntelDX2 processors + case 8: // IntelDX4 OverDrive processors, IntelDX4 processors + default: + *Type = INTEL_i486; + break; + } + case 5: + switch (Model) { + case 1: // Pentium OverDrive processor for Pentium processor (60, 66), + // Pentium processors (60, 66) + case 2: // Pentium OverDrive processor for Pentium processor (75, 90, + // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, + // 150, 166, 200) + case 3: // Pentium OverDrive processors for Intel486 processor-based + // systems + *Type = INTEL_PENTIUM; + break; + case 4: // Pentium OverDrive processor with MMX technology for Pentium + // processor (75, 90, 100, 120, 133), Pentium processor with + // MMX technology (166, 200) + *Type = INTEL_PENTIUM; + *Subtype = INTEL_PENTIUM_MMX; + break; + default: + *Type = INTEL_PENTIUM; + break; + } + case 6: + switch (Model) { + case 0x01: // Pentium Pro processor + *Type = INTEL_PENTIUM_PRO; + break; + case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor, + // model 03 + case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor, + // model 05, and Intel Celeron processor, model 05 + case 0x06: // Celeron processor, model 06 + *Type = INTEL_PENTIUM_II; + break; + case 0x07: // Pentium III processor, model 07, and Pentium III Xeon + // processor, model 07 + case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor, + // model 08, and Celeron processor, model 08 + case 0x0a: // Pentium III Xeon processor, model 0Ah + case 0x0b: // Pentium III processor, model 0Bh + *Type = INTEL_PENTIUM_III; + break; + case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09. + case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model + // 0Dh. All processors are manufactured using the 90 nm process. + case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579 + // Integrated Processor with Intel QuickAssist Technology + *Type = INTEL_PENTIUM_M; + break; + case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model + // 0Eh. All processors are manufactured using the 65 nm process. + *Type = INTEL_CORE_DUO; + break; // yonah + case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile + // processor, Intel Core 2 Quad processor, Intel Core 2 Quad + // mobile processor, Intel Core 2 Extreme processor, Intel + // Pentium Dual-Core processor, Intel Xeon processor, model + // 0Fh. All processors are manufactured using the 65 nm process. + case 0x16: // Intel Celeron processor model 16h. All processors are + // manufactured using the 65 nm process + *Type = INTEL_CORE2; // "core2" + *Subtype = INTEL_CORE2_65; + break; + case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model + // 17h. All processors are manufactured using the 45 nm process. + // + // 45nm: Penryn , Wolfdale, Yorkfield (XE) + case 0x1d: // Intel Xeon processor MP. All processors are manufactured using + // the 45 nm process. + *Type = INTEL_CORE2; // "penryn" + *Subtype = INTEL_CORE2_45; + break; + case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All + // processors are manufactured using the 45 nm process. + case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. + // As found in a Summer 2010 model iMac. + case 0x1f: + case 0x2e: // Nehalem EX + *Type = INTEL_COREI7; // "nehalem" + *Subtype = INTEL_COREI7_NEHALEM; + break; + case 0x25: // Intel Core i7, laptop version. + case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All + // processors are manufactured using the 32 nm process. + case 0x2f: // Westmere EX + *Type = INTEL_COREI7; // "westmere" + *Subtype = INTEL_COREI7_WESTMERE; + break; + case 0x2a: // Intel Core i7 processor. All processors are manufactured + // using the 32 nm process. + case 0x2d: + *Type = INTEL_COREI7; //"sandybridge" + *Subtype = INTEL_COREI7_SANDYBRIDGE; + break; + case 0x3a: + case 0x3e: // Ivy Bridge EP + *Type = INTEL_COREI7; // "ivybridge" + *Subtype = INTEL_COREI7_IVYBRIDGE; + break; + + // Haswell: + case 0x3c: + case 0x3f: + case 0x45: + case 0x46: + *Type = INTEL_COREI7; // "haswell" + *Subtype = INTEL_COREI7_HASWELL; + break; + + // Broadwell: + case 0x3d: + case 0x47: + case 0x4f: + case 0x56: + *Type = INTEL_COREI7; // "broadwell" + *Subtype = INTEL_COREI7_BROADWELL; + break; + + // Skylake: + case 0x4e: + *Type = INTEL_COREI7; // "skylake-avx512" + *Subtype = INTEL_COREI7_SKYLAKE_AVX512; + break; + case 0x5e: + *Type = INTEL_COREI7; // "skylake" + *Subtype = INTEL_COREI7_SKYLAKE; + break; + + case 0x1c: // Most 45 nm Intel Atom processors + case 0x26: // 45 nm Atom Lincroft + case 0x27: // 32 nm Atom Medfield + case 0x35: // 32 nm Atom Midview + case 0x36: // 32 nm Atom Midview + *Type = INTEL_ATOM; + *Subtype = INTEL_ATOM_BONNELL; + break; // "bonnell" + + // Atom Silvermont codes from the Intel software optimization guide. + case 0x37: + case 0x4a: + case 0x4d: + case 0x5a: + case 0x5d: + case 0x4c: // really airmont + *Type = INTEL_ATOM; + *Subtype = INTEL_ATOM_SILVERMONT; + break; // "silvermont" + + case 0x57: + *Type = INTEL_XEONPHI; // knl + *Subtype = INTEL_KNIGHTS_LANDING; + break; + + default: // Unknown family 6 CPU, try to guess. + if (Features & (1 << FEATURE_AVX512)) { + *Type = INTEL_XEONPHI; // knl + *Subtype = INTEL_KNIGHTS_LANDING; + break; + } + if (Features & (1 << FEATURE_ADX)) { + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_BROADWELL; + break; + } + if (Features & (1 << FEATURE_AVX2)) { + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_HASWELL; + break; + } + if (Features & (1 << FEATURE_AVX)) { + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_SANDYBRIDGE; + break; + } + if (Features & (1 << FEATURE_SSE4_2)) { + if (Features & (1 << FEATURE_MOVBE)) { + *Type = INTEL_ATOM; + *Subtype = INTEL_ATOM_SILVERMONT; + } else { + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_NEHALEM; + } + break; + } + if (Features & (1 << FEATURE_SSE4_1)) { + *Type = INTEL_CORE2; // "penryn" + *Subtype = INTEL_CORE2_45; + break; + } + if (Features & (1 << FEATURE_SSSE3)) { + if (Features & (1 << FEATURE_MOVBE)) { + *Type = INTEL_ATOM; + *Subtype = INTEL_ATOM_BONNELL; // "bonnell" + } else { + *Type = INTEL_CORE2; // "core2" + *Subtype = INTEL_CORE2_65; + } + break; + } + if (Features & (1 << FEATURE_EM64T)) { + *Type = INTEL_X86_64; + break; // x86-64 + } + if (Features & (1 << FEATURE_SSE2)) { + *Type = INTEL_PENTIUM_M; + break; + } + if (Features & (1 << FEATURE_SSE)) { + *Type = INTEL_PENTIUM_III; + break; + } + if (Features & (1 << FEATURE_MMX)) { + *Type = INTEL_PENTIUM_II; + break; + } + *Type = INTEL_PENTIUM_PRO; + break; + } + case 15: { + switch (Model) { + case 0: // Pentium 4 processor, Intel Xeon processor. All processors are + // model 00h and manufactured using the 0.18 micron process. + case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon + // processor MP, and Intel Celeron processor. All processors are + // model 01h and manufactured using the 0.18 micron process. + case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, + // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron + // processor, and Mobile Intel Celeron processor. All processors + // are model 02h and manufactured using the 0.13 micron process. + *Type = + ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); + break; + + case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D + // processor. All processors are model 03h and manufactured using + // the 90 nm process. + case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, + // Pentium D processor, Intel Xeon processor, Intel Xeon + // processor MP, Intel Celeron D processor. All processors are + // model 04h and manufactured using the 90 nm process. + case 6: // Pentium 4 processor, Pentium D processor, Pentium processor + // Extreme Edition, Intel Xeon processor, Intel Xeon processor + // MP, Intel Celeron D processor. All processors are model 06h + // and manufactured using the 65 nm process. + *Type = + ((Features & (1 << FEATURE_EM64T)) ? INTEL_NOCONA : INTEL_PRESCOTT); + break; + + default: + *Type = + ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); + break; + } + } + default: + break; /*"generic"*/ + } +} + +static void getAMDProcessorTypeAndSubtype(unsigned int Family, + unsigned int Model, + unsigned int Features, unsigned *Type, + unsigned *Subtype) { + // FIXME: this poorly matches the generated SubtargetFeatureKV table. There + // appears to be no way to generate the wide variety of AMD-specific targets + // from the information returned from CPUID. + switch (Family) { + case 4: + *Type = AMD_i486; + case 5: + *Type = AMDPENTIUM; + switch (Model) { + case 6: + case 7: + *Subtype = AMDPENTIUM_K6; + break; // "k6" + case 8: + *Subtype = AMDPENTIUM_K62; + break; // "k6-2" + case 9: + case 13: + *Subtype = AMDPENTIUM_K63; + break; // "k6-3" + case 10: + *Subtype = AMDPENTIUM_GEODE; + break; // "geode" + default: + break; + } + case 6: + *Type = AMDATHLON; + switch (Model) { + case 4: + *Subtype = AMDATHLON_TBIRD; + break; // "athlon-tbird" + case 6: + case 7: + case 8: + *Subtype = AMDATHLON_MP; + break; // "athlon-mp" + case 10: + *Subtype = AMDATHLON_XP; + break; // "athlon-xp" + default: + break; + } + case 15: + *Type = AMDATHLON; + if (Features & (1 << FEATURE_SSE3)) { + *Subtype = AMDATHLON_K8SSE3; + break; // "k8-sse3" + } + switch (Model) { + case 1: + *Subtype = AMDATHLON_OPTERON; + break; // "opteron" + case 5: + *Subtype = AMDATHLON_FX; + break; // "athlon-fx"; also opteron + default: + *Subtype = AMDATHLON_64; + break; // "athlon64" + } + case 16: + *Type = AMDFAM10H; // "amdfam10" + switch (Model) { + case 2: + *Subtype = AMDFAM10H_BARCELONA; + break; + case 4: + *Subtype = AMDFAM10H_SHANGHAI; + break; + case 8: + *Subtype = AMDFAM10H_ISTANBUL; + break; + default: + break; + } + case 20: + *Type = AMDFAM14H; + *Subtype = AMD_BTVER1; + break; // "btver1"; + case 21: + *Type = AMDFAM15H; + if (!(Features & + (1 << FEATURE_AVX))) { // If no AVX support, provide a sane fallback. + *Subtype = AMD_BTVER1; + break; // "btver1" + } + if (Model >= 0x50 && Model <= 0x6f) { + *Subtype = AMDFAM15H_BDVER4; + break; // "bdver4"; 50h-6Fh: Excavator + } + if (Model >= 0x30 && Model <= 0x3f) { + *Subtype = AMDFAM15H_BDVER3; + break; // "bdver3"; 30h-3Fh: Steamroller + } + if (Model >= 0x10 && Model <= 0x1f) { + *Subtype = AMDFAM15H_BDVER2; + break; // "bdver2"; 10h-1Fh: Piledriver + } + if (Model <= 0x0f) { + *Subtype = AMDFAM15H_BDVER1; + break; // "bdver1"; 00h-0Fh: Bulldozer + } + break; + case 22: + *Type = AMDFAM16H; + if (!(Features & + (1 << FEATURE_AVX))) { // If no AVX support provide a sane fallback. + *Subtype = AMD_BTVER1; + break; // "btver1"; + } + *Subtype = AMD_BTVER2; + break; // "btver2" + default: + break; // "generic" + } +} + +static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, + unsigned MaxLeaf) { + unsigned Features = 0; + unsigned int EAX, EBX; + Features |= (((EDX >> 23) & 1) << FEATURE_MMX); + Features |= (((EDX >> 25) & 1) << FEATURE_SSE); + Features |= (((EDX >> 26) & 1) << FEATURE_SSE2); + Features |= (((ECX >> 0) & 1) << FEATURE_SSE3); + Features |= (((ECX >> 9) & 1) << FEATURE_SSSE3); + Features |= (((ECX >> 19) & 1) << FEATURE_SSE4_1); + Features |= (((ECX >> 20) & 1) << FEATURE_SSE4_2); + Features |= (((ECX >> 22) & 1) << FEATURE_MOVBE); + + // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV + // indicates that the AVX registers will be saved and restored on context + // switch, then we have full AVX support. + const unsigned AVXBits = (1 << 27) | (1 << 28); + bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && + ((EAX & 0x6) == 0x6); + bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); + bool HasLeaf7 = MaxLeaf >= 0x7; + getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); + bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); + bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); + bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); + Features |= (HasAVX << FEATURE_AVX); + Features |= (HasAVX2 << FEATURE_AVX2); + Features |= (HasAVX512 << FEATURE_AVX512); + Features |= (HasAVX512Save << FEATURE_AVX512SAVE); + Features |= (HasADX << FEATURE_ADX); + + getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + Features |= (((EDX >> 29) & 0x1) << FEATURE_EM64T); + return Features; +} + +#ifdef HAVE_INIT_PRIORITY +#define CONSTRUCTOR_PRIORITY (101) +#else +#define CONSTRUCTOR_PRIORITY +#endif + +int __cpu_indicator_init(void) + __attribute__((constructor CONSTRUCTOR_PRIORITY)); + +struct __processor_model { + unsigned int __cpu_vendor; + unsigned int __cpu_type; + unsigned int __cpu_subtype; + unsigned int __cpu_features[1]; +} __cpu_model = {0, 0, 0, {0}}; + +/* A constructor function that is sets __cpu_model and __cpu_features with + the right values. This needs to run only once. This constructor is + given the highest priority and it should run before constructors without + the priority set. However, it still runs after ifunc initializers and + needs to be called explicitly there. */ + +int __attribute__((constructor CONSTRUCTOR_PRIORITY)) +__cpu_indicator_init(void) { + unsigned int EAX, EBX, ECX, EDX; + unsigned int MaxLeaf = 5; + unsigned int Vendor; + unsigned int Model, Family, Brand_id; + unsigned int Features = 0; + + /* This function needs to run just once. */ + if (__cpu_model.__cpu_vendor) + return 0; + + if (!isCpuIdSupported()) + return -1; + + /* Assume cpuid insn present. Run in level 0 to get vendor id. */ + getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX); + + if (MaxLeaf < 1) { + __cpu_model.__cpu_vendor = VENDOR_OTHER; + return -1; + } + getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); + detectX86FamilyModel(EAX, &Family, &Model); + Brand_id = EBX & 0xff; + + /* Find available features. */ + Features = getAvailableFeatures(ECX, EDX, MaxLeaf); + __cpu_model.__cpu_features[0] = Features; + + if (Vendor == SIG_INTEL) { + /* Get CPU type. */ + getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, + &(__cpu_model.__cpu_type), + &(__cpu_model.__cpu_subtype)); + __cpu_model.__cpu_vendor = VENDOR_INTEL; + } else if (Vendor == SIG_AMD) { + /* Get CPU type. */ + getAMDProcessorTypeAndSubtype(Family, Model, Features, + &(__cpu_model.__cpu_type), + &(__cpu_model.__cpu_subtype)); + __cpu_model.__cpu_vendor = VENDOR_AMD; + } else + __cpu_model.__cpu_vendor = VENDOR_OTHER; + + assert(__cpu_model.__cpu_vendor < VENDOR_MAX); + assert(__cpu_model.__cpu_type < CPU_TYPE_MAX); + assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); + + return 0; +} + +#endif diff --git a/contrib/compiler-rt/lib/builtins/emutls.c b/contrib/compiler-rt/lib/builtins/emutls.c index 09e79568bd56..eccbf53366e3 100644 --- a/contrib/compiler-rt/lib/builtins/emutls.c +++ b/contrib/compiler-rt/lib/builtins/emutls.c @@ -27,9 +27,14 @@ * If xyz has non-zero initial value, __emutls_v.xyz's "value" * will point to __emutls_t.xyz, which has the initial value. */ +typedef unsigned int gcc_word __attribute__((mode(word))); typedef struct __emutls_control { - size_t size; /* size of the object in bytes */ - size_t align; /* alignment of the object in bytes */ + /* Must use gcc_word here, instead of size_t, to match GCC. When + gcc_word is larger than size_t, the upper extra bits are all + zeros. We can use variables of size_t to operate on size and + align. */ + gcc_word size; /* size of the object in bytes */ + gcc_word align; /* alignment of the object in bytes */ union { uintptr_t index; /* data[index-1] is the object address */ void* address; /* object address, when in single thread env */ @@ -67,21 +72,20 @@ static __inline void emutls_memalign_free(void *base) { /* Emulated TLS objects are always allocated at run-time. */ static __inline void *emutls_allocate_object(__emutls_control *control) { /* Use standard C types, check with gcc's emutls.o. */ - typedef unsigned int gcc_word __attribute__((mode(word))); typedef unsigned int gcc_pointer __attribute__((mode(pointer))); - COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word)); COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer)); COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*)); size_t size = control->size; size_t align = control->align; + void* base; if (align < sizeof(void*)) align = sizeof(void*); /* Make sure that align is power of 2. */ if ((align & (align - 1)) != 0) abort(); - void* base = emutls_memalign_alloc(align, size); + base = emutls_memalign_alloc(align, size); if (control->value) memcpy(base, control->value, size); else @@ -160,12 +164,14 @@ emutls_get_address_array(uintptr_t index) { emutls_address_array* array = pthread_getspecific(emutls_pthread_key); if (array == NULL) { uintptr_t new_size = emutls_new_data_array_size(index); - array = calloc(new_size + 1, sizeof(void*)); + array = malloc(new_size * sizeof(void *) + sizeof(emutls_address_array)); + if (array) + memset(array->data, 0, new_size * sizeof(void*)); emutls_check_array_set_size(array, new_size); } else if (index > array->size) { uintptr_t orig_size = array->size; uintptr_t new_size = emutls_new_data_array_size(index); - array = realloc(array, (new_size + 1) * sizeof(void*)); + array = realloc(array, new_size * sizeof(void *) + sizeof(emutls_address_array)); if (array) memset(array->data + orig_size, 0, (new_size - orig_size) * sizeof(void*)); diff --git a/contrib/compiler-rt/lib/builtins/floatdidf.c b/contrib/compiler-rt/lib/builtins/floatdidf.c index a300c9f312d2..2b023ad08beb 100644 --- a/contrib/compiler-rt/lib/builtins/floatdidf.c +++ b/contrib/compiler-rt/lib/builtins/floatdidf.c @@ -16,7 +16,7 @@ /* Returns: convert a to a double, rounding toward even. */ -/* Assumption: double is a IEEE 64 bit floating point type +/* Assumption: double is a IEEE 64 bit floating point type * di_int is a 64 bit integral type */ @@ -32,16 +32,16 @@ ARM_EABI_FNALIAS(l2d, floatdidf) COMPILER_RT_ABI double __floatdidf(di_int a) { - static const double twop52 = 4503599627370496.0; // 0x1.0p52 - static const double twop32 = 4294967296.0; // 0x1.0p32 - - union { int64_t x; double d; } low = { .d = twop52 }; - - const double high = (int32_t)(a >> 32) * twop32; - low.x |= a & INT64_C(0x00000000ffffffff); - - const double result = (high - twop52) + low.d; - return result; + static const double twop52 = 4503599627370496.0; // 0x1.0p52 + static const double twop32 = 4294967296.0; // 0x1.0p32 + + union { int64_t x; double d; } low = { .d = twop52 }; + + const double high = (int32_t)(a >> 32) * twop32; + low.x |= a & INT64_C(0x00000000ffffffff); + + const double result = (high - twop52) + low.d; + return result; } #else @@ -98,10 +98,10 @@ __floatdidf(di_int a) /* a is now rounded to DBL_MANT_DIG bits */ } double_bits fb; - fb.u.high = ((su_int)s & 0x80000000) | /* sign */ - ((e + 1023) << 20) | /* exponent */ - ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ - fb.u.low = (su_int)a; /* mantissa-low */ + fb.u.s.high = ((su_int)s & 0x80000000) | /* sign */ + ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.s.low = (su_int)a; /* mantissa-low */ return fb.f; } #endif diff --git a/contrib/compiler-rt/lib/builtins/floattidf.c b/contrib/compiler-rt/lib/builtins/floattidf.c index 6331ba57376f..2702a3c8a2db 100644 --- a/contrib/compiler-rt/lib/builtins/floattidf.c +++ b/contrib/compiler-rt/lib/builtins/floattidf.c @@ -10,7 +10,7 @@ * This file implements __floattidf for the compiler_rt library. * * ===----------------------------------------------------------------------=== - */ + */ #include "int_lib.h" @@ -18,11 +18,11 @@ /* Returns: convert a to a double, rounding toward even.*/ -/* Assumption: double is a IEEE 64 bit floating point type +/* Assumption: double is a IEEE 64 bit floating point type * ti_int is a 128 bit integral type */ -/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ COMPILER_RT_ABI double __floattidf(ti_int a) diff --git a/contrib/compiler-rt/lib/builtins/floatundidf.c b/contrib/compiler-rt/lib/builtins/floatundidf.c index 67aa86e5e5b8..cfd3a7a3b33f 100644 --- a/contrib/compiler-rt/lib/builtins/floatundidf.c +++ b/contrib/compiler-rt/lib/builtins/floatundidf.c @@ -14,7 +14,7 @@ /* Returns: convert a to a double, rounding toward even. */ -/* Assumption: double is a IEEE 64 bit floating point type +/* Assumption: double is a IEEE 64 bit floating point type * du_int is a 64 bit integral type */ @@ -32,24 +32,24 @@ ARM_EABI_FNALIAS(ul2d, floatundidf) COMPILER_RT_ABI double __floatundidf(du_int a) { - static const double twop52 = 4503599627370496.0; // 0x1.0p52 - static const double twop84 = 19342813113834066795298816.0; // 0x1.0p84 - static const double twop84_plus_twop52 = 19342813118337666422669312.0; // 0x1.00000001p84 - - union { uint64_t x; double d; } high = { .d = twop84 }; - union { uint64_t x; double d; } low = { .d = twop52 }; - - high.x |= a >> 32; - low.x |= a & UINT64_C(0x00000000ffffffff); - - const double result = (high.d - twop84_plus_twop52) + low.d; - return result; + static const double twop52 = 4503599627370496.0; // 0x1.0p52 + static const double twop84 = 19342813113834066795298816.0; // 0x1.0p84 + static const double twop84_plus_twop52 = 19342813118337666422669312.0; // 0x1.00000001p84 + + union { uint64_t x; double d; } high = { .d = twop84 }; + union { uint64_t x; double d; } low = { .d = twop52 }; + + high.x |= a >> 32; + low.x |= a & UINT64_C(0x00000000ffffffff); + + const double result = (high.d - twop84_plus_twop52) + low.d; + return result; } #else /* Support for systems that don't have hardware floating-point; there are no flags to * set, and we don't want to code-gen to an unknown soft-float implementation. - */ + */ COMPILER_RT_ABI double __floatundidf(du_int a) @@ -98,9 +98,9 @@ __floatundidf(du_int a) /* a is now rounded to DBL_MANT_DIG bits */ } double_bits fb; - fb.u.high = ((e + 1023) << 20) | /* exponent */ - ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ - fb.u.low = (su_int)a; /* mantissa-low */ + fb.u.s.high = ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.s.low = (su_int)a; /* mantissa-low */ return fb.f; } #endif diff --git a/contrib/compiler-rt/lib/builtins/floatuntidf.c b/contrib/compiler-rt/lib/builtins/floatuntidf.c index 06202d9679ee..960265d80772 100644 --- a/contrib/compiler-rt/lib/builtins/floatuntidf.c +++ b/contrib/compiler-rt/lib/builtins/floatuntidf.c @@ -18,7 +18,7 @@ /* Returns: convert a to a double, rounding toward even. */ -/* Assumption: double is a IEEE 64 bit floating point type +/* Assumption: double is a IEEE 64 bit floating point type * tu_int is a 128 bit integral type */ diff --git a/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c b/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c index ed544d30b809..29e5be30712f 100644 --- a/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c +++ b/contrib/compiler-rt/lib/builtins/gcc_personality_v0.c @@ -131,6 +131,26 @@ static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding) return result; } +#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ + !defined(__ARM_DWARF_EH__) +#define USING_ARM_EHABI 1 +_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception *, + struct _Unwind_Context *); +#endif + +static inline _Unwind_Reason_Code +continueUnwind(struct _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context) { +#if USING_ARM_EHABI + /* + * On ARM EHABI the personality routine is responsible for actually + * unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). + */ + if (__gnu_unwind_frame(exceptionObject, context) != _URC_OK) + return _URC_FAILURE; +#endif + return _URC_CONTINUE_UNWIND; +} /* * The C compiler makes references to __gcc_personality_v0 in @@ -147,6 +167,11 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions, uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, struct _Unwind_Context *context) +#elif USING_ARM_EHABI +/* The ARM EHABI personality routine has a different signature. */ +COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0( + _Unwind_State state, struct _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context) #else COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, @@ -156,13 +181,19 @@ __gcc_personality_v0(int version, _Unwind_Action actions, { /* Since C does not have catch clauses, there is nothing to do during */ /* phase 1 (the search phase). */ - if ( actions & _UA_SEARCH_PHASE ) - return _URC_CONTINUE_UNWIND; - +#if USING_ARM_EHABI + /* After resuming from a cleanup we should also continue on to the next + * frame straight away. */ + if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) +#else + if ( actions & _UA_SEARCH_PHASE ) +#endif + return continueUnwind(exceptionObject, context); + /* There is nothing to do if there is no LSDA for this frame. */ const uint8_t* lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context); if ( lsda == (uint8_t*) 0 ) - return _URC_CONTINUE_UNWIND; + return continueUnwind(exceptionObject, context); uintptr_t pc = _Unwind_GetIP(context)-1; uintptr_t funcStart = _Unwind_GetRegionStart(context); @@ -205,6 +236,6 @@ __gcc_personality_v0(int version, _Unwind_Action actions, } /* No landing pad found, continue unwinding. */ - return _URC_CONTINUE_UNWIND; + return continueUnwind(exceptionObject, context); } diff --git a/contrib/compiler-rt/lib/builtins/i386/ashldi3.S b/contrib/compiler-rt/lib/builtins/i386/ashldi3.S index 3fbd73903842..6f05dcf74443 100644 --- a/contrib/compiler-rt/lib/builtins/i386/ashldi3.S +++ b/contrib/compiler-rt/lib/builtins/i386/ashldi3.S @@ -56,3 +56,6 @@ END_COMPILERRT_FUNCTION(__ashldi3) #endif // __SSE2__ #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/ashrdi3.S b/contrib/compiler-rt/lib/builtins/i386/ashrdi3.S index 8f4742481b42..206369f360aa 100644 --- a/contrib/compiler-rt/lib/builtins/i386/ashrdi3.S +++ b/contrib/compiler-rt/lib/builtins/i386/ashrdi3.S @@ -67,3 +67,6 @@ END_COMPILERRT_FUNCTION(__ashrdi3) #endif // __SSE2__ #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/divdi3.S b/contrib/compiler-rt/lib/builtins/i386/divdi3.S index 2cb0ddd4c29f..2fb4bdcad90d 100644 --- a/contrib/compiler-rt/lib/builtins/i386/divdi3.S +++ b/contrib/compiler-rt/lib/builtins/i386/divdi3.S @@ -160,3 +160,6 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3) END_COMPILERRT_FUNCTION(__divdi3) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/floatdidf.S b/contrib/compiler-rt/lib/builtins/i386/floatdidf.S index dcc32f8ed85d..d75dfe62d6a7 100644 --- a/contrib/compiler-rt/lib/builtins/i386/floatdidf.S +++ b/contrib/compiler-rt/lib/builtins/i386/floatdidf.S @@ -37,3 +37,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatdidf) END_COMPILERRT_FUNCTION(__floatdidf) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/floatdisf.S b/contrib/compiler-rt/lib/builtins/i386/floatdisf.S index f64276703607..0874eaaa9a98 100644 --- a/contrib/compiler-rt/lib/builtins/i386/floatdisf.S +++ b/contrib/compiler-rt/lib/builtins/i386/floatdisf.S @@ -30,3 +30,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatdisf) END_COMPILERRT_FUNCTION(__floatdisf) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/floatdixf.S b/contrib/compiler-rt/lib/builtins/i386/floatdixf.S index 839b0434c0c6..1044ef55a1a8 100644 --- a/contrib/compiler-rt/lib/builtins/i386/floatdixf.S +++ b/contrib/compiler-rt/lib/builtins/i386/floatdixf.S @@ -28,3 +28,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatdixf) END_COMPILERRT_FUNCTION(__floatdixf) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/floatundidf.S b/contrib/compiler-rt/lib/builtins/i386/floatundidf.S index 8058c2ac0aed..fe032348e829 100644 --- a/contrib/compiler-rt/lib/builtins/i386/floatundidf.S +++ b/contrib/compiler-rt/lib/builtins/i386/floatundidf.S @@ -50,3 +50,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundidf) END_COMPILERRT_FUNCTION(__floatundidf) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/floatundisf.S b/contrib/compiler-rt/lib/builtins/i386/floatundisf.S index 94c97e25aa8c..16000b576026 100644 --- a/contrib/compiler-rt/lib/builtins/i386/floatundisf.S +++ b/contrib/compiler-rt/lib/builtins/i386/floatundisf.S @@ -103,3 +103,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf) END_COMPILERRT_FUNCTION(__floatundisf) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/floatundixf.S b/contrib/compiler-rt/lib/builtins/i386/floatundixf.S index 814b52f941d8..c935670cb52f 100644 --- a/contrib/compiler-rt/lib/builtins/i386/floatundixf.S +++ b/contrib/compiler-rt/lib/builtins/i386/floatundixf.S @@ -41,3 +41,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundixf) END_COMPILERRT_FUNCTION(__floatundixf) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/lshrdi3.S b/contrib/compiler-rt/lib/builtins/i386/lshrdi3.S index b80f11a3806b..53e95cf76527 100644 --- a/contrib/compiler-rt/lib/builtins/i386/lshrdi3.S +++ b/contrib/compiler-rt/lib/builtins/i386/lshrdi3.S @@ -57,3 +57,6 @@ END_COMPILERRT_FUNCTION(__lshrdi3) #endif // __SSE2__ #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/moddi3.S b/contrib/compiler-rt/lib/builtins/i386/moddi3.S index b9cee9d7aa70..a5bf9ce8ea0f 100644 --- a/contrib/compiler-rt/lib/builtins/i386/moddi3.S +++ b/contrib/compiler-rt/lib/builtins/i386/moddi3.S @@ -164,3 +164,6 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3) END_COMPILERRT_FUNCTION(__moddi3) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/muldi3.S b/contrib/compiler-rt/lib/builtins/i386/muldi3.S index 15b6b4998456..12394606421c 100644 --- a/contrib/compiler-rt/lib/builtins/i386/muldi3.S +++ b/contrib/compiler-rt/lib/builtins/i386/muldi3.S @@ -28,3 +28,6 @@ DEFINE_COMPILERRT_FUNCTION(__muldi3) END_COMPILERRT_FUNCTION(__muldi3) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/udivdi3.S b/contrib/compiler-rt/lib/builtins/i386/udivdi3.S index 41b2edf03e34..727613639b12 100644 --- a/contrib/compiler-rt/lib/builtins/i386/udivdi3.S +++ b/contrib/compiler-rt/lib/builtins/i386/udivdi3.S @@ -113,3 +113,6 @@ DEFINE_COMPILERRT_FUNCTION(__udivdi3) END_COMPILERRT_FUNCTION(__udivdi3) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/i386/umoddi3.S b/contrib/compiler-rt/lib/builtins/i386/umoddi3.S index a190a7d397d2..763e821946c0 100644 --- a/contrib/compiler-rt/lib/builtins/i386/umoddi3.S +++ b/contrib/compiler-rt/lib/builtins/i386/umoddi3.S @@ -124,3 +124,6 @@ DEFINE_COMPILERRT_FUNCTION(__umoddi3) END_COMPILERRT_FUNCTION(__umoddi3) #endif // __i386__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/int_lib.h b/contrib/compiler-rt/lib/builtins/int_lib.h index 0fb03ff0e31f..44e0a28fc076 100644 --- a/contrib/compiler-rt/lib/builtins/int_lib.h +++ b/contrib/compiler-rt/lib/builtins/int_lib.h @@ -43,11 +43,7 @@ #else # define ARM_EABI_FNALIAS(aeabi_name, name) -# if defined(__arm__) && defined(_WIN32) && (!defined(_MSC_VER) || defined(__clang__)) -# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) -# else -# define COMPILER_RT_ABI -# endif +# define COMPILER_RT_ABI #endif #ifdef _MSC_VER diff --git a/contrib/compiler-rt/lib/builtins/ppc/restFP.S b/contrib/compiler-rt/lib/builtins/ppc/restFP.S index 95032897c0da..507e756e18b1 100644 --- a/contrib/compiler-rt/lib/builtins/ppc/restFP.S +++ b/contrib/compiler-rt/lib/builtins/ppc/restFP.S @@ -41,3 +41,6 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(restFP) lwz r0,8(r1) mtlr r0 blr + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/ppc/saveFP.S b/contrib/compiler-rt/lib/builtins/ppc/saveFP.S index 72bd459f4cc0..20b06fff53d9 100644 --- a/contrib/compiler-rt/lib/builtins/ppc/saveFP.S +++ b/contrib/compiler-rt/lib/builtins/ppc/saveFP.S @@ -38,3 +38,6 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(saveFP) stfd f31,-8(r1) stw r0,8(r1) blr + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/x86_64/floatundidf.S b/contrib/compiler-rt/lib/builtins/x86_64/floatundidf.S index 3cd5d02a743a..094a68dc3cd4 100644 --- a/contrib/compiler-rt/lib/builtins/x86_64/floatundidf.S +++ b/contrib/compiler-rt/lib/builtins/x86_64/floatundidf.S @@ -47,3 +47,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundidf) END_COMPILERRT_FUNCTION(__floatundidf) #endif // __x86_64__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/x86_64/floatundisf.S b/contrib/compiler-rt/lib/builtins/x86_64/floatundisf.S index 61952f40470c..7c9f75e188eb 100644 --- a/contrib/compiler-rt/lib/builtins/x86_64/floatundisf.S +++ b/contrib/compiler-rt/lib/builtins/x86_64/floatundisf.S @@ -33,3 +33,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf) END_COMPILERRT_FUNCTION(__floatundisf) #endif // __x86_64__ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/builtins/x86_64/floatundixf.S b/contrib/compiler-rt/lib/builtins/x86_64/floatundixf.S index 92961c89115d..28a096b71373 100644 --- a/contrib/compiler-rt/lib/builtins/x86_64/floatundixf.S +++ b/contrib/compiler-rt/lib/builtins/x86_64/floatundixf.S @@ -66,3 +66,6 @@ END_COMPILERRT_FUNCTION(__floatundixf) #endif // __x86_64__ */ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/contrib/compiler-rt/lib/cfi/cfi.cc b/contrib/compiler-rt/lib/cfi/cfi.cc index 711866f3fa0c..ca2cf8f30617 100644 --- a/contrib/compiler-rt/lib/cfi/cfi.cc +++ b/contrib/compiler-rt/lib/cfi/cfi.cc @@ -11,16 +11,11 @@ // //===----------------------------------------------------------------------===// -// FIXME: Intercept dlopen/dlclose. -// FIXME: Support diagnostic mode. -// FIXME: Harden: -// * mprotect shadow, use mremap for updates -// * something else equally important - #include #include #include #include +#include typedef ElfW(Phdr) Elf_Phdr; typedef ElfW(Ehdr) Elf_Ehdr; @@ -31,19 +26,55 @@ typedef ElfW(Ehdr) Elf_Ehdr; #include "ubsan/ubsan_init.h" #include "ubsan/ubsan_flags.h" -static uptr __cfi_shadow; +#ifdef CFI_ENABLE_DIAG +#include "ubsan/ubsan_handlers.h" +#endif + +namespace __cfi { + +#define kCfiShadowLimitsStorageSize 4096 // 1 page +// Lets hope that the data segment is mapped with 4K pages. +// The pointer to the cfi shadow region is stored at the start of this page. +// The rest of the page is unused and re-mapped read-only. +static union { + char space[kCfiShadowLimitsStorageSize]; + struct { + uptr start; + uptr size; + } limits; +} cfi_shadow_limits_storage + __attribute__((aligned(kCfiShadowLimitsStorageSize))); static constexpr uptr kShadowGranularity = 12; static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096 static constexpr uint16_t kInvalidShadow = 0; static constexpr uint16_t kUncheckedShadow = 0xFFFFU; -static uint16_t *mem_to_shadow(uptr x) { - return (uint16_t *)(__cfi_shadow + ((x >> kShadowGranularity) << 1)); +// Get the start address of the CFI shadow region. +uptr GetShadow() { + return cfi_shadow_limits_storage.limits.start; } -typedef int (*CFICheckFn)(u64, void *); +uptr GetShadowSize() { + return cfi_shadow_limits_storage.limits.size; +} +// This will only work while the shadow is not allocated. +void SetShadowSize(uptr size) { + cfi_shadow_limits_storage.limits.size = size; +} + +uptr MemToShadowOffset(uptr x) { + return (x >> kShadowGranularity) << 1; +} + +uint16_t *MemToShadow(uptr x, uptr shadow_base) { + return (uint16_t *)(shadow_base + MemToShadowOffset(x)); +} + +typedef int (*CFICheckFn)(u64, void *, void *); + +// This class reads and decodes the shadow contents. class ShadowValue { uptr addr; uint16_t v; @@ -61,49 +92,91 @@ public: return reinterpret_cast(p); } - // Load a shadow valud for the given application memory address. + // Load a shadow value for the given application memory address. static const ShadowValue load(uptr addr) { - return ShadowValue(addr, *mem_to_shadow(addr)); + uptr shadow_base = GetShadow(); + uptr shadow_offset = MemToShadowOffset(addr); + if (shadow_offset > GetShadowSize()) + return ShadowValue(addr, kInvalidShadow); + else + return ShadowValue( + addr, *reinterpret_cast(shadow_base + shadow_offset)); } }; -static void fill_shadow_constant(uptr begin, uptr end, uint16_t v) { - assert(v == kInvalidShadow || v == kUncheckedShadow); - uint16_t *shadow_begin = mem_to_shadow(begin); - uint16_t *shadow_end = mem_to_shadow(end - 1) + 1; - memset(shadow_begin, v, (shadow_end - shadow_begin) * sizeof(*shadow_begin)); +class ShadowBuilder { + uptr shadow_; + +public: + // Allocate a new empty shadow (for the entire address space) on the side. + void Start(); + // Mark the given address range as unchecked. + // This is used for uninstrumented libraries like libc. + // Any CFI check with a target in that range will pass. + void AddUnchecked(uptr begin, uptr end); + // Mark the given address range as belonging to a library with the given + // cfi_check function. + void Add(uptr begin, uptr end, uptr cfi_check); + // Finish shadow construction. Atomically switch the current active shadow + // region with the newly constructed one and deallocate the former. + void Install(); +}; + +void ShadowBuilder::Start() { + shadow_ = (uptr)MmapNoReserveOrDie(GetShadowSize(), "CFI shadow"); + VReport(1, "CFI: shadow at %zx .. %zx\n", shadow_, shadow_ + GetShadowSize()); } -static void fill_shadow(uptr begin, uptr end, uptr cfi_check) { +void ShadowBuilder::AddUnchecked(uptr begin, uptr end) { + uint16_t *shadow_begin = MemToShadow(begin, shadow_); + uint16_t *shadow_end = MemToShadow(end - 1, shadow_) + 1; + memset(shadow_begin, kUncheckedShadow, + (shadow_end - shadow_begin) * sizeof(*shadow_begin)); +} + +void ShadowBuilder::Add(uptr begin, uptr end, uptr cfi_check) { assert((cfi_check & (kShadowAlign - 1)) == 0); // Don't fill anything below cfi_check. We can not represent those addresses // in the shadow, and must make sure at codegen to place all valid call // targets above cfi_check. - uptr p = Max(begin, cfi_check); - uint16_t *s = mem_to_shadow(p); - uint16_t *s_end = mem_to_shadow(end - 1) + 1; - uint16_t sv = ((p - cfi_check) >> kShadowGranularity) + 1; + begin = Max(begin, cfi_check); + uint16_t *s = MemToShadow(begin, shadow_); + uint16_t *s_end = MemToShadow(end - 1, shadow_) + 1; + uint16_t sv = ((begin - cfi_check) >> kShadowGranularity) + 1; for (; s < s_end; s++, sv++) *s = sv; +} - // Sanity checks. - uptr q = p & ~(kShadowAlign - 1); - for (; q < end; q += kShadowAlign) { - assert((uptr)ShadowValue::load(q).get_cfi_check() == cfi_check); - assert((uptr)ShadowValue::load(q + kShadowAlign / 2).get_cfi_check() == - cfi_check); - assert((uptr)ShadowValue::load(q + kShadowAlign - 1).get_cfi_check() == - cfi_check); +#if SANITIZER_LINUX +void ShadowBuilder::Install() { + MprotectReadOnly(shadow_, GetShadowSize()); + uptr main_shadow = GetShadow(); + if (main_shadow) { + // Update. + void *res = mremap((void *)shadow_, GetShadowSize(), GetShadowSize(), + MREMAP_MAYMOVE | MREMAP_FIXED, (void *)main_shadow); + CHECK(res != MAP_FAILED); + } else { + // Initial setup. + CHECK_EQ(kCfiShadowLimitsStorageSize, GetPageSizeCached()); + CHECK_EQ(0, GetShadow()); + cfi_shadow_limits_storage.limits.start = shadow_; + MprotectReadOnly((uptr)&cfi_shadow_limits_storage, + sizeof(cfi_shadow_limits_storage)); + CHECK_EQ(shadow_, GetShadow()); } } +#else +#error not implemented +#endif // This is a workaround for a glibc bug: // https://sourceware.org/bugzilla/show_bug.cgi?id=15199 // Other platforms can, hopefully, just do // dlopen(RTLD_NOLOAD | RTLD_LAZY) // dlsym("__cfi_check"). -static uptr find_cfi_check_in_dso(dl_phdr_info *info) { +uptr find_cfi_check_in_dso(dl_phdr_info *info) { const ElfW(Dyn) *dynamic = nullptr; for (int i = 0; i < info->dlpi_phnum; ++i) { if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) { @@ -157,11 +230,13 @@ static uptr find_cfi_check_in_dso(dl_phdr_info *info) { return 0; } -static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) { +int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) { uptr cfi_check = find_cfi_check_in_dso(info); if (cfi_check) VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check); + ShadowBuilder *b = reinterpret_cast(data); + for (int i = 0; i < info->dlpi_phnum; i++) { const Elf_Phdr *phdr = &info->dlpi_phdr[i]; if (phdr->p_type == PT_LOAD) { @@ -174,28 +249,69 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) { uptr cur_end = cur_beg + phdr->p_memsz; if (cfi_check) { VReport(1, " %zx .. %zx\n", cur_beg, cur_end); - fill_shadow(cur_beg, cur_end, cfi_check ? cfi_check : (uptr)(-1)); + b->Add(cur_beg, cur_end, cfi_check); } else { - fill_shadow_constant(cur_beg, cur_end, kUncheckedShadow); + b->AddUnchecked(cur_beg, cur_end); } } } return 0; } -// Fill shadow for the initial libraries. -static void init_shadow() { - dl_iterate_phdr(dl_iterate_phdr_cb, nullptr); +// Init or update shadow for the current set of loaded libraries. +void UpdateShadow() { + ShadowBuilder b; + b.Start(); + dl_iterate_phdr(dl_iterate_phdr_cb, &b); + b.Install(); } -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -void __cfi_slowpath(u64 CallSiteTypeId, void *Ptr) { +void InitShadow() { + CHECK_EQ(0, GetShadow()); + CHECK_EQ(0, GetShadowSize()); + + uptr vma = GetMaxVirtualAddress(); + // Shadow is 2 -> 2**kShadowGranularity. + SetShadowSize((vma >> (kShadowGranularity - 1)) + 1); + VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, GetShadowSize()); + + UpdateShadow(); +} + +THREADLOCAL int in_loader; +BlockingMutex shadow_update_lock(LINKER_INITIALIZED); + +void EnterLoader() { + if (in_loader == 0) { + shadow_update_lock.Lock(); + } + ++in_loader; +} + +void ExitLoader() { + CHECK(in_loader > 0); + --in_loader; + UpdateShadow(); + if (in_loader == 0) { + shadow_update_lock.Unlock(); + } +} + +ALWAYS_INLINE void CfiSlowPathCommon(u64 CallSiteTypeId, void *Ptr, + void *DiagData) { uptr Addr = (uptr)Ptr; VReport(3, "__cfi_slowpath: %llx, %p\n", CallSiteTypeId, Ptr); ShadowValue sv = ShadowValue::load(Addr); if (sv.is_invalid()) { - VReport(2, "CFI: invalid memory region for a function pointer (shadow==0): %p\n", Ptr); - Die(); + VReport(1, "CFI: invalid memory region for a check target: %p\n", Ptr); +#ifdef CFI_ENABLE_DIAG + if (DiagData) { + __ubsan_handle_cfi_check_fail( + reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr, false); + return; + } +#endif + Trap(); } if (sv.is_unchecked()) { VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr); @@ -203,10 +319,10 @@ void __cfi_slowpath(u64 CallSiteTypeId, void *Ptr) { } CFICheckFn cfi_check = sv.get_cfi_check(); VReport(2, "__cfi_check at %p\n", cfi_check); - cfi_check(CallSiteTypeId, Ptr); + cfi_check(CallSiteTypeId, Ptr, DiagData); } -static void InitializeFlags() { +void InitializeFlags() { SetCommonFlagsDefaults(); #ifdef CFI_ENABLE_DIAG __ubsan::Flags *uf = __ubsan::flags(); @@ -227,15 +343,54 @@ static void InitializeFlags() { ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS")); #endif - SetVerbosity(common_flags()->verbosity); + InitializeCommonFlags(); - if (Verbosity()) ReportUnrecognizedFlags(); + if (Verbosity()) + ReportUnrecognizedFlags(); if (common_flags()->help) { cfi_parser.PrintFlagDescriptions(); } } +} // namespace __cfi + +using namespace __cfi; + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__cfi_slowpath(u64 CallSiteTypeId, void *Ptr) { + CfiSlowPathCommon(CallSiteTypeId, Ptr, nullptr); +} + +#ifdef CFI_ENABLE_DIAG +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) { + CfiSlowPathCommon(CallSiteTypeId, Ptr, DiagData); +} +#endif + +// Setup shadow for dlopen()ed libraries. +// The actual shadow setup happens after dlopen() returns, which means that +// a library can not be a target of any CFI checks while its constructors are +// running. It's unclear how to fix this without some extra help from libc. +// In glibc, mmap inside dlopen is not interceptable. +// Maybe a seccomp-bpf filter? +// We could insert a high-priority constructor into the library, but that would +// not help with the uninstrumented libraries. +INTERCEPTOR(void*, dlopen, const char *filename, int flag) { + EnterLoader(); + void *handle = REAL(dlopen)(filename, flag); + ExitLoader(); + return handle; +} + +INTERCEPTOR(int, dlclose, void *handle) { + EnterLoader(); + int res = REAL(dlclose)(handle); + ExitLoader(); + return res; +} + extern "C" SANITIZER_INTERFACE_ATTRIBUTE #if !SANITIZER_CAN_USE_PREINIT_ARRAY // On ELF platforms, the constructor is invoked using .preinit_array (see below) @@ -244,16 +399,10 @@ __attribute__((constructor(0))) void __cfi_init() { SanitizerToolName = "CFI"; InitializeFlags(); + InitShadow(); - uptr vma = GetMaxVirtualAddress(); - // Shadow is 2 -> 2**kShadowGranularity. - uptr shadow_size = (vma >> (kShadowGranularity - 1)) + 1; - VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, shadow_size); - void *shadow = MmapNoReserveOrDie(shadow_size, "CFI shadow"); - VReport(1, "CFI: shadow at %zx .. %zx\n", shadow, - reinterpret_cast(shadow) + shadow_size); - __cfi_shadow = (uptr)shadow; - init_shadow(); + INTERCEPT_FUNCTION(dlopen); + INTERCEPT_FUNCTION(dlclose); #ifdef CFI_ENABLE_DIAG __ubsan::InitAsPlugin(); diff --git a/contrib/compiler-rt/lib/dfsan/dfsan.cc b/contrib/compiler-rt/lib/dfsan/dfsan.cc index 7285f202d060..4156000a1cce 100644 --- a/contrib/compiler-rt/lib/dfsan/dfsan.cc +++ b/contrib/compiler-rt/lib/dfsan/dfsan.cc @@ -362,12 +362,13 @@ static void InitializeFlags() { RegisterCommonFlags(&parser); RegisterDfsanFlags(&parser, &flags()); parser.ParseString(GetEnv("DFSAN_OPTIONS")); - SetVerbosity(common_flags()->verbosity); + InitializeCommonFlags(); if (Verbosity()) ReportUnrecognizedFlags(); if (common_flags()->help) parser.PrintFlagDescriptions(); } static void InitializePlatformEarly() { + AvoidCVE_2016_2143(); #ifdef DFSAN_RUNTIME_VMA __dfsan::vmaSize = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); @@ -411,7 +412,7 @@ static void dfsan_init(int argc, char **argv, char **envp) { // case by disabling memory protection when ASLR is disabled. uptr init_addr = (uptr)&dfsan_init; if (!(init_addr >= UnusedAddr() && init_addr < AppAddr())) - MmapNoAccess(UnusedAddr(), AppAddr() - UnusedAddr()); + MmapFixedNoAccess(UnusedAddr(), AppAddr() - UnusedAddr()); InitializeInterceptors(); diff --git a/contrib/compiler-rt/lib/esan/cache_frag.cpp b/contrib/compiler-rt/lib/esan/cache_frag.cpp new file mode 100644 index 000000000000..a3e612daceb1 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/cache_frag.cpp @@ -0,0 +1,208 @@ +//===-- cache_frag.cpp ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// This file contains cache fragmentation-specific code. +//===----------------------------------------------------------------------===// + +#include "esan.h" +#include "esan_flags.h" +#include "sanitizer_common/sanitizer_addrhashmap.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_placement_new.h" +#include + +namespace __esan { + +//===-- Struct field access counter runtime -------------------------------===// + +// This should be kept consistent with LLVM's EfficiencySanitizer StructInfo. +struct StructInfo { + const char *StructName; + u32 Size; + u32 NumFields; + u32 *FieldOffset; // auxiliary struct field info. + u32 *FieldSize; // auxiliary struct field info. + const char **FieldTypeName; // auxiliary struct field info. + u64 *FieldCounters; + u64 *ArrayCounter; + bool hasAuxFieldInfo() { return FieldOffset != nullptr; } +}; + +// This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo. +// The tool-specific information per compilation unit (module). +struct CacheFragInfo { + const char *UnitName; + u32 NumStructs; + StructInfo *Structs; +}; + +struct StructCounter { + StructInfo *Struct; + u64 Count; // The total access count of the struct. + u64 Ratio; // Difference ratio for the struct layout access. +}; + +// We use StructHashMap to keep track of an unique copy of StructCounter. +typedef AddrHashMap StructHashMap; +struct Context { + StructHashMap StructMap; + u32 NumStructs; + u64 TotalCount; // The total access count of all structs. +}; +static Context *Ctx; + +static void reportStructSummary() { + // FIXME: provide a better struct field access summary report. + Report("%s: total struct field access count = %llu\n", SanitizerToolName, + Ctx->TotalCount); +} + +// FIXME: we are still exploring proper ways to evaluate the difference between +// struct field counts. Currently, we use a simple formula to calculate the +// difference ratio: V1/V2. +static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) { + if (Val2 > Val1) { + Swap(Val1, Val2); + } + if (Val2 == 0) + Val2 = 1; + return (Val1 / Val2); +} + +static void reportStructCounter(StructHashMap::Handle &Handle) { + const u32 TypePrintLimit = 512; + const char *type, *start, *end; + StructInfo *Struct = Handle->Struct; + // Union field address calculation is done via bitcast instead of GEP, + // so the count for union is always 0. + // We skip the union report to avoid confusion. + if (strncmp(Struct->StructName, "union.", 6) == 0) + return; + // Remove the '.' after class/struct during print. + if (strncmp(Struct->StructName, "class.", 6) == 0) { + type = "class"; + start = &Struct->StructName[6]; + } else { + type = "struct"; + start = &Struct->StructName[7]; + } + // Remove the suffixes with '#' during print. + end = strchr(start, '#'); + CHECK(end != nullptr); + Report(" %s %.*s\n", type, end - start, start); + Report(" size = %u, count = %llu, ratio = %llu, array access = %llu\n", + Struct->Size, Handle->Count, Handle->Ratio, *Struct->ArrayCounter); + if (Struct->hasAuxFieldInfo()) { + for (u32 i = 0; i < Struct->NumFields; ++i) { + Report(" #%2u: offset = %u,\t size = %u," + "\t count = %llu,\t type = %.*s\n", + i, Struct->FieldOffset[i], Struct->FieldSize[i], + Struct->FieldCounters[i], TypePrintLimit, Struct->FieldTypeName[i]); + } + } else { + for (u32 i = 0; i < Struct->NumFields; ++i) { + Report(" #%2u: count = %llu\n", i, Struct->FieldCounters[i]); + } + } +} + +static void computeStructRatio(StructHashMap::Handle &Handle) { + Handle->Ratio = 0; + Handle->Count = Handle->Struct->FieldCounters[0]; + for (u32 i = 1; i < Handle->Struct->NumFields; ++i) { + Handle->Count += Handle->Struct->FieldCounters[i]; + Handle->Ratio += computeDifferenceRatio( + Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]); + } + Ctx->TotalCount += Handle->Count; + if (Handle->Ratio >= (u64)getFlags()->report_threshold || + (Verbosity() >= 1 && Handle->Count > 0)) + reportStructCounter(Handle); +} + +static void registerStructInfo(CacheFragInfo *CacheFrag) { + for (u32 i = 0; i < CacheFrag->NumStructs; ++i) { + StructInfo *Struct = &CacheFrag->Structs[i]; + StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters); + if (H.created()) { + VPrintf(2, " Register %s: %u fields\n", Struct->StructName, + Struct->NumFields); + H->Struct = Struct; + ++Ctx->NumStructs; + } else { + VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, + Struct->NumFields); + } + } +} + +static void unregisterStructInfo(CacheFragInfo *CacheFrag) { + // FIXME: if the library is unloaded before finalizeCacheFrag, we should + // collect the result for later report. + for (u32 i = 0; i < CacheFrag->NumStructs; ++i) { + StructInfo *Struct = &CacheFrag->Structs[i]; + StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true); + if (H.exists()) { + VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName, + Struct->NumFields); + // FIXME: we should move this call to finalizeCacheFrag once we can + // iterate over the hash map there. + computeStructRatio(H); + --Ctx->NumStructs; + } else { + VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, + Struct->NumFields); + } + } + static bool Reported = false; + if (Ctx->NumStructs == 0 && !Reported) { + Reported = true; + reportStructSummary(); + } +} + +//===-- Init/exit functions -----------------------------------------------===// + +void processCacheFragCompilationUnitInit(void *Ptr) { + CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; + VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, + CacheFrag->UnitName, CacheFrag->NumStructs); + registerStructInfo(CacheFrag); +} + +void processCacheFragCompilationUnitExit(void *Ptr) { + CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; + VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, + CacheFrag->UnitName, CacheFrag->NumStructs); + unregisterStructInfo(CacheFrag); +} + +void initializeCacheFrag() { + VPrintf(2, "in esan::%s\n", __FUNCTION__); + // We use placement new to initialize Ctx before C++ static initializaion. + // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap. + static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1]; + Ctx = new (CtxMem) Context(); + Ctx->NumStructs = 0; +} + +int finalizeCacheFrag() { + VPrintf(2, "in esan::%s\n", __FUNCTION__); + return 0; +} + +void reportCacheFrag() { + VPrintf(2, "in esan::%s\n", __FUNCTION__); + // FIXME: Not yet implemented. We need to iterate over all of the + // compilation unit data. +} + +} // namespace __esan diff --git a/contrib/compiler-rt/lib/esan/cache_frag.h b/contrib/compiler-rt/lib/esan/cache_frag.h new file mode 100644 index 000000000000..646d3f85ed97 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/cache_frag.h @@ -0,0 +1,29 @@ +//===-- cache_frag.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Header for cache-fragmentation-specific code. +//===----------------------------------------------------------------------===// + +#ifndef CACHE_FRAG_H +#define CACHE_FRAG_H + +namespace __esan { + +void processCacheFragCompilationUnitInit(void *Ptr); +void processCacheFragCompilationUnitExit(void *Ptr); + +void initializeCacheFrag(); +int finalizeCacheFrag(); +void reportCacheFrag(); + +} // namespace __esan + +#endif // CACHE_FRAG_H diff --git a/contrib/compiler-rt/lib/esan/esan.cpp b/contrib/compiler-rt/lib/esan/esan.cpp new file mode 100644 index 000000000000..2fb77894d4fb --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan.cpp @@ -0,0 +1,270 @@ +//===-- esan.cpp ----------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Main file (entry points) for the Esan run-time. +//===----------------------------------------------------------------------===// + +#include "esan.h" +#include "esan_flags.h" +#include "esan_interface_internal.h" +#include "esan_shadow.h" +#include "cache_frag.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "working_set.h" + +// See comment below. +extern "C" { +extern void __cxa_atexit(void (*function)(void)); +} + +namespace __esan { + +bool EsanIsInitialized; +bool EsanDuringInit; +ShadowMapping Mapping; + +// Different tools use different scales within the same shadow mapping scheme. +// The scale used here must match that used by the compiler instrumentation. +// This array is indexed by the ToolType enum. +static const uptr ShadowScale[] = { + 0, // ESAN_None. + 2, // ESAN_CacheFrag: 4B:1B, so 4 to 1 == >>2. + 6, // ESAN_WorkingSet: 64B:1B, so 64 to 1 == >>6. +}; + +// We are combining multiple performance tuning tools under the umbrella of +// one EfficiencySanitizer super-tool. Most of our tools have very similar +// memory access instrumentation, shadow memory mapping, libc interception, +// etc., and there is typically more shared code than distinct code. +// +// We are not willing to dispatch on tool dynamically in our fastpath +// instrumentation: thus, which tool to use is a static option selected +// at compile time and passed to __esan_init(). +// +// We are willing to pay the overhead of tool dispatch in the slowpath to more +// easily share code. We expect to only come here rarely. +// If this becomes a performance hit, we can add separate interface +// routines for each subtool (e.g., __esan_cache_frag_aligned_load_4). +// But for libc interceptors, we'll have to do one of the following: +// A) Add multiple-include support to sanitizer_common_interceptors.inc, +// instantiate it separately for each tool, and call the selected +// tool's intercept setup code. +// B) Build separate static runtime libraries, one for each tool. +// C) Completely split the tools into separate sanitizers. + +void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite) { + VPrintf(3, "in esan::%s %p: %c %p %d\n", __FUNCTION__, PC, + IsWrite ? 'w' : 'r', Addr, Size); + if (__esan_which_tool == ESAN_CacheFrag) { + // TODO(bruening): add shadow mapping and update shadow bits here. + // We'll move this to cache_frag.cpp once we have something. + } else if (__esan_which_tool == ESAN_WorkingSet) { + processRangeAccessWorkingSet(PC, Addr, Size, IsWrite); + } +} + +bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int)) { + if (__esan_which_tool == ESAN_WorkingSet) + return processWorkingSetSignal(SigNum, Handler, Result); + return true; +} + +bool processSigaction(int SigNum, const void *Act, void *OldAct) { + if (__esan_which_tool == ESAN_WorkingSet) + return processWorkingSetSigaction(SigNum, Act, OldAct); + return true; +} + +bool processSigprocmask(int How, void *Set, void *OldSet) { + if (__esan_which_tool == ESAN_WorkingSet) + return processWorkingSetSigprocmask(How, Set, OldSet); + return true; +} + +#if SANITIZER_DEBUG +static bool verifyShadowScheme() { + // Sanity checks for our shadow mapping scheme. + uptr AppStart, AppEnd; + if (Verbosity() >= 3) { + for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { + VPrintf(3, "App #%d: [%zx-%zx) (%zuGB)\n", i, AppStart, AppEnd, + (AppEnd - AppStart) >> 30); + } + } + for (int Scale = 0; Scale < 8; ++Scale) { + Mapping.initialize(Scale); + if (Verbosity() >= 3) { + VPrintf(3, "\nChecking scale %d\n", Scale); + uptr ShadowStart, ShadowEnd; + for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { + VPrintf(3, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, + ShadowEnd, (ShadowEnd - ShadowStart) >> 30); + } + for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { + VPrintf(3, "Shadow(Shadow) #%d: [%zx-%zx)\n", i, + appToShadow(ShadowStart), appToShadow(ShadowEnd - 1)+1); + } + } + for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { + DCHECK(isAppMem(AppStart)); + DCHECK(!isAppMem(AppStart - 1)); + DCHECK(isAppMem(AppEnd - 1)); + DCHECK(!isAppMem(AppEnd)); + DCHECK(!isShadowMem(AppStart)); + DCHECK(!isShadowMem(AppEnd - 1)); + DCHECK(isShadowMem(appToShadow(AppStart))); + DCHECK(isShadowMem(appToShadow(AppEnd - 1))); + // Double-shadow checks. + DCHECK(!isShadowMem(appToShadow(appToShadow(AppStart)))); + DCHECK(!isShadowMem(appToShadow(appToShadow(AppEnd - 1)))); + } + // Ensure no shadow regions overlap each other. + uptr ShadowAStart, ShadowBStart, ShadowAEnd, ShadowBEnd; + for (int i = 0; getShadowRegion(i, &ShadowAStart, &ShadowAEnd); ++i) { + for (int j = 0; getShadowRegion(j, &ShadowBStart, &ShadowBEnd); ++j) { + DCHECK(i == j || ShadowAStart >= ShadowBEnd || + ShadowAEnd <= ShadowBStart); + } + } + } + return true; +} +#endif + +static void initializeShadow() { + verifyAddressSpace(); + + DCHECK(verifyShadowScheme()); + + Mapping.initialize(ShadowScale[__esan_which_tool]); + + VPrintf(1, "Shadow scale=%d offset=%p\n", Mapping.Scale, Mapping.Offset); + + uptr ShadowStart, ShadowEnd; + for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { + VPrintf(1, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, ShadowEnd, + (ShadowEnd - ShadowStart) >> 30); + + uptr Map; + if (__esan_which_tool == ESAN_WorkingSet) { + // We want to identify all shadow pages that are touched so we start + // out inaccessible. + Map = (uptr)MmapFixedNoAccess(ShadowStart, ShadowEnd- ShadowStart, + "shadow"); + } else { + Map = (uptr)MmapFixedNoReserve(ShadowStart, ShadowEnd - ShadowStart, + "shadow"); + } + if (Map != ShadowStart) { + Printf("FATAL: EfficiencySanitizer failed to map its shadow memory.\n"); + Die(); + } + + if (common_flags()->no_huge_pages_for_shadow) + NoHugePagesInRegion(ShadowStart, ShadowEnd - ShadowStart); + if (common_flags()->use_madv_dontdump) + DontDumpShadowMemory(ShadowStart, ShadowEnd - ShadowStart); + + // TODO: Call MmapNoAccess() on in-between regions. + } +} + +void initializeLibrary(ToolType Tool) { + // We assume there is only one thread during init, but we need to + // guard against double-init when we're (re-)called from an + // early interceptor. + if (EsanIsInitialized || EsanDuringInit) + return; + EsanDuringInit = true; + CHECK(Tool == __esan_which_tool); + SanitizerToolName = "EfficiencySanitizer"; + CacheBinaryName(); + initializeFlags(); + + // Intercepting libc _exit or exit via COMMON_INTERCEPTOR_ON_EXIT only + // finalizes on an explicit exit call by the app. To handle a normal + // exit we register an atexit handler. + ::__cxa_atexit((void (*)())finalizeLibrary); + + VPrintf(1, "in esan::%s\n", __FUNCTION__); + if (__esan_which_tool <= ESAN_None || __esan_which_tool >= ESAN_Max) { + Printf("ERROR: unknown tool %d requested\n", __esan_which_tool); + Die(); + } + + initializeShadow(); + if (__esan_which_tool == ESAN_WorkingSet) + initializeShadowWorkingSet(); + + initializeInterceptors(); + + if (__esan_which_tool == ESAN_CacheFrag) { + initializeCacheFrag(); + } else if (__esan_which_tool == ESAN_WorkingSet) { + initializeWorkingSet(); + } + + EsanIsInitialized = true; + EsanDuringInit = false; +} + +int finalizeLibrary() { + VPrintf(1, "in esan::%s\n", __FUNCTION__); + if (__esan_which_tool == ESAN_CacheFrag) { + return finalizeCacheFrag(); + } else if (__esan_which_tool == ESAN_WorkingSet) { + return finalizeWorkingSet(); + } + return 0; +} + +void reportResults() { + VPrintf(1, "in esan::%s\n", __FUNCTION__); + if (__esan_which_tool == ESAN_CacheFrag) { + return reportCacheFrag(); + } else if (__esan_which_tool == ESAN_WorkingSet) { + return reportWorkingSet(); + } +} + +void processCompilationUnitInit(void *Ptr) { + VPrintf(2, "in esan::%s\n", __FUNCTION__); + if (__esan_which_tool == ESAN_CacheFrag) { + DCHECK(Ptr != nullptr); + processCacheFragCompilationUnitInit(Ptr); + } else { + DCHECK(Ptr == nullptr); + } +} + +// This is called when the containing module is unloaded. +// For the main executable module, this is called after finalizeLibrary. +void processCompilationUnitExit(void *Ptr) { + VPrintf(2, "in esan::%s\n", __FUNCTION__); + if (__esan_which_tool == ESAN_CacheFrag) { + DCHECK(Ptr != nullptr); + processCacheFragCompilationUnitExit(Ptr); + } else { + DCHECK(Ptr == nullptr); + } +} + +unsigned int getSampleCount() { + VPrintf(1, "in esan::%s\n", __FUNCTION__); + if (__esan_which_tool == ESAN_WorkingSet) { + return getSampleCountWorkingSet(); + } + return 0; +} + +} // namespace __esan diff --git a/contrib/compiler-rt/lib/esan/esan.h b/contrib/compiler-rt/lib/esan/esan.h new file mode 100644 index 000000000000..5a0dde627888 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan.h @@ -0,0 +1,60 @@ +//===-- esan.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Main internal esan header file. +// +// Ground rules: +// - C++ run-time should not be used (static CTORs, RTTI, exceptions, static +// function-scope locals) +// - All functions/classes/etc reside in namespace __esan, except for those +// declared in esan_interface_internal.h. +// - Platform-specific files should be used instead of ifdefs (*). +// - No system headers included in header files (*). +// - Platform specific headers included only into platform-specific files (*). +// +// (*) Except when inlining is critical for performance. +//===----------------------------------------------------------------------===// + +#ifndef ESAN_H +#define ESAN_H + +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_common.h" +#include "esan_interface_internal.h" + +namespace __esan { + +extern bool EsanIsInitialized; +extern bool EsanDuringInit; + +void initializeLibrary(ToolType Tool); +int finalizeLibrary(); +void reportResults(); +unsigned int getSampleCount(); +// Esan creates the variable per tool per compilation unit at compile time +// and passes its pointer Ptr to the runtime library. +void processCompilationUnitInit(void *Ptr); +void processCompilationUnitExit(void *Ptr); +void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite); +void initializeInterceptors(); + +// Platform-dependent routines. +void verifyAddressSpace(); +bool fixMmapAddr(void **Addr, SIZE_T Size, int Flags); +uptr checkMmapResult(uptr Addr, SIZE_T Size); +// The return value indicates whether to call the real version or not. +bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int)); +bool processSigaction(int SigNum, const void *Act, void *OldAct); +bool processSigprocmask(int How, void *Set, void *OldSet); + +} // namespace __esan + +#endif // ESAN_H diff --git a/contrib/compiler-rt/lib/esan/esan.syms.extra b/contrib/compiler-rt/lib/esan/esan.syms.extra new file mode 100644 index 000000000000..d6397d4c350f --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan.syms.extra @@ -0,0 +1,4 @@ +__esan_init +__esan_exit +__esan_aligned* +__esan_unaligned* diff --git a/contrib/compiler-rt/lib/esan/esan_circular_buffer.h b/contrib/compiler-rt/lib/esan/esan_circular_buffer.h new file mode 100644 index 000000000000..9ce102d04d8f --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_circular_buffer.h @@ -0,0 +1,96 @@ +//===-- esan_circular_buffer.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Circular buffer data structure. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_common.h" + +namespace __esan { + +// A circular buffer for POD data whose memory is allocated using mmap. +// There are two usage models: one is to use initialize/free (for global +// instances) and the other is to use placement new with the +// constructor and to call the destructor or free (they are equivalent). +template +class CircularBuffer { + public: + // To support global instances we cannot initialize any field in the + // default constructor. + explicit CircularBuffer() {} + CircularBuffer(uptr BufferCapacity) { + initialize(BufferCapacity); + WasConstructed = true; + } + ~CircularBuffer() { + if (WasConstructed) // Else caller will call free() explicitly. + free(); + } + void initialize(uptr BufferCapacity) { + Capacity = BufferCapacity; + // MmapOrDie rounds up to the page size for us. + Data = (T *)MmapOrDie(Capacity * sizeof(T), "CircularBuffer"); + StartIdx = 0; + Count = 0; + WasConstructed = false; + } + void free() { + UnmapOrDie(Data, Capacity * sizeof(T)); + } + T &operator[](uptr Idx) { + CHECK_LT(Idx, Count); + uptr ArrayIdx = (StartIdx + Idx) % Capacity; + return Data[ArrayIdx]; + } + const T &operator[](uptr Idx) const { + CHECK_LT(Idx, Count); + uptr ArrayIdx = (StartIdx + Idx) % Capacity; + return Data[ArrayIdx]; + } + void push_back(const T &Item) { + CHECK_GT(Capacity, 0); + uptr ArrayIdx = (StartIdx + Count) % Capacity; + Data[ArrayIdx] = Item; + if (Count < Capacity) + ++Count; + else + StartIdx = (StartIdx + 1) % Capacity; + } + T &back() { + CHECK_GT(Count, 0); + uptr ArrayIdx = (StartIdx + Count - 1) % Capacity; + return Data[ArrayIdx]; + } + void pop_back() { + CHECK_GT(Count, 0); + --Count; + } + uptr size() const { + return Count; + } + void clear() { + StartIdx = 0; + Count = 0; + } + bool empty() const { return size() == 0; } + + private: + CircularBuffer(const CircularBuffer&); + void operator=(const CircularBuffer&); + + bool WasConstructed; + T *Data; + uptr Capacity; + uptr StartIdx; + uptr Count; +}; + +} // namespace __esan diff --git a/contrib/compiler-rt/lib/esan/esan_flags.cpp b/contrib/compiler-rt/lib/esan/esan_flags.cpp new file mode 100644 index 000000000000..3b047e28be22 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_flags.cpp @@ -0,0 +1,58 @@ +//===-- esan_flags.cc -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Esan flag parsing logic. +//===----------------------------------------------------------------------===// + +#include "esan_flags.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_flags.h" + +namespace __esan { + +static const char EsanOptsEnv[] = "ESAN_OPTIONS"; + +Flags EsanFlagsDontUseDirectly; + +void Flags::setDefaults() { +#define ESAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "esan_flags.inc" +#undef ESAN_FLAG +} + +static void registerEsanFlags(FlagParser *Parser, Flags *F) { +#define ESAN_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(Parser, #Name, Description, &F->Name); +#include "esan_flags.inc" +#undef ESAN_FLAG +} + +void initializeFlags() { + SetCommonFlagsDefaults(); + Flags *F = getFlags(); + F->setDefaults(); + + FlagParser Parser; + registerEsanFlags(&Parser, F); + RegisterCommonFlags(&Parser); + Parser.ParseString(GetEnv(EsanOptsEnv)); + + InitializeCommonFlags(); + if (Verbosity()) + ReportUnrecognizedFlags(); + if (common_flags()->help) + Parser.PrintFlagDescriptions(); + + __sanitizer_set_report_path(common_flags()->log_path); +} + +} // namespace __esan diff --git a/contrib/compiler-rt/lib/esan/esan_flags.h b/contrib/compiler-rt/lib/esan/esan_flags.h new file mode 100644 index 000000000000..c8f4ef5ab2b5 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_flags.h @@ -0,0 +1,41 @@ +//===-- esan_flags.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Esan runtime flags. +//===----------------------------------------------------------------------===// + +#ifndef ESAN_FLAGS_H +#define ESAN_FLAGS_H + +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_flag_parser.h" + +namespace __esan { + +class Flags { +public: +#define ESAN_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "esan_flags.inc" +#undef ESAN_FLAG + + void setDefaults(); +}; + +extern Flags EsanFlagsDontUseDirectly; +inline Flags *getFlags() { + return &EsanFlagsDontUseDirectly; +} + +void initializeFlags(); + +} // namespace __esan + +#endif // ESAN_FLAGS_H diff --git a/contrib/compiler-rt/lib/esan/esan_flags.inc b/contrib/compiler-rt/lib/esan/esan_flags.inc new file mode 100644 index 000000000000..5687caca2989 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_flags.inc @@ -0,0 +1,56 @@ +//===-- esan_flags.inc ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Esan runtime flags. +// +//===----------------------------------------------------------------------===// + +#ifndef ESAN_FLAG +# error "Define ESAN_FLAG prior to including this file!" +#endif + +// ESAN_FLAG(Type, Name, DefaultValue, Description) +// See COMMON_FLAG in sanitizer_flags.inc for more details. + +//===----------------------------------------------------------------------===// +// Cross-tool options +//===----------------------------------------------------------------------===// + +ESAN_FLAG(int, cache_line_size, 64, + "The number of bytes in a cache line. For the working-set tool, this " + "cannot be changed without also changing the compiler " + "instrumentation.") + +//===----------------------------------------------------------------------===// +// Working set tool options +//===----------------------------------------------------------------------===// + +ESAN_FLAG(bool, record_snapshots, true, + "Working set tool: whether to sample snapshots during a run.") + +// Typical profiling uses a 10ms timer. Our snapshots take some work +// to scan memory so we reduce to 20ms. +// To disable samples, turn off record_snapshots. +ESAN_FLAG(int, sample_freq, 20, + "Working set tool: sampling frequency in milliseconds.") + +// This controls the difference in frequency between each successive series +// of snapshots. There are 8 in total, with number 0 using sample_freq. +// Number N samples number N-1 every (1 << snapshot_step) instance of N-1. +ESAN_FLAG(int, snapshot_step, 2, "Working set tool: the log of the sampling " + "performed for the next-higher-frequency snapshot series.") + +//===----------------------------------------------------------------------===// +// Cache Fragmentation tool options +//===----------------------------------------------------------------------===// + +// The difference information of a struct is reported if the struct's difference +// score is greater than the report_threshold. +ESAN_FLAG(int, report_threshold, 1<<10, "Cache-frag tool: the struct difference" + " score threshold for reporting.") diff --git a/contrib/compiler-rt/lib/esan/esan_interceptors.cpp b/contrib/compiler-rt/lib/esan/esan_interceptors.cpp new file mode 100644 index 000000000000..647f010852b0 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_interceptors.cpp @@ -0,0 +1,547 @@ +//===-- esan_interceptors.cpp ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Interception routines for the esan run-time. +//===----------------------------------------------------------------------===// + +#include "esan.h" +#include "esan_shadow.h" +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_stacktrace.h" + +using namespace __esan; // NOLINT + +#define CUR_PC() (StackTrace::GetCurrentPc()) + +//===----------------------------------------------------------------------===// +// Interception via sanitizer common interceptors +//===----------------------------------------------------------------------===// + +// Get the per-platform defines for what is possible to intercept +#include "sanitizer_common/sanitizer_platform_interceptors.h" + +// TODO(bruening): tsan disables several interceptors (getpwent, etc.) claiming +// that interception is a perf hit: should we do the same? + +// We have no need to intercept: +#undef SANITIZER_INTERCEPT_TLS_GET_ADDR + +// TODO(bruening): the common realpath interceptor assumes malloc is +// intercepted! We should try to parametrize that, though we'll +// intercept malloc soon ourselves and can then remove this undef. +#undef SANITIZER_INTERCEPT_REALPATH + +// We provide our own version: +#undef SANITIZER_INTERCEPT_SIGPROCMASK + +#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!EsanIsInitialized) + +#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) +#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ + INTERCEPT_FUNCTION_VER(name, ver) + +// We must initialize during early interceptors, to support tcmalloc. +// This means that for some apps we fully initialize prior to +// __esan_init() being called. +// We currently do not use ctx. +#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ + do { \ + if (UNLIKELY(COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)) { \ + if (!UNLIKELY(EsanDuringInit)) \ + initializeLibrary(__esan_which_tool); \ + return REAL(func)(__VA_ARGS__); \ + } \ + ctx = nullptr; \ + (void)ctx; \ + } while (false) + +#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ + COMMON_INTERCEPTOR_ENTER(ctx, func, __VA_ARGS__) + +#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ + processRangeAccess(CUR_PC(), (uptr)ptr, size, true) + +#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ + processRangeAccess(CUR_PC(), (uptr)ptr, size, false) + +// This is only called if the app explicitly calls exit(), not on +// a normal exit. +#define COMMON_INTERCEPTOR_ON_EXIT(ctx) finalizeLibrary() + +#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ + do { \ + (void)(ctx); \ + (void)(file); \ + (void)(path); \ + } while (false) +#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ + do { \ + (void)(ctx); \ + (void)(file); \ + } while (false) +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ + do { \ + (void)(filename); \ + (void)(handle); \ + } while (false) +#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \ + do { \ + (void)(ctx); \ + (void)(u); \ + } while (false) +#define COMMON_INTERCEPTOR_RELEASE(ctx, u) \ + do { \ + (void)(ctx); \ + (void)(u); \ + } while (false) +#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ + do { \ + (void)(ctx); \ + (void)(path); \ + } while (false) +#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ + do { \ + (void)(ctx); \ + (void)(fd); \ + } while (false) +#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ + do { \ + (void)(ctx); \ + (void)(fd); \ + } while (false) +#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \ + do { \ + (void)(ctx); \ + (void)(fd); \ + } while (false) +#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ + do { \ + (void)(ctx); \ + (void)(fd); \ + (void)(newfd); \ + } while (false) +#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ + do { \ + (void)(ctx); \ + (void)(name); \ + } while (false) +#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ + do { \ + (void)(ctx); \ + (void)(thread); \ + (void)(name); \ + } while (false) +#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) +#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \ + do { \ + (void)(ctx); \ + (void)(m); \ + } while (false) +#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ + do { \ + (void)(ctx); \ + (void)(m); \ + } while (false) +#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \ + do { \ + (void)(ctx); \ + (void)(m); \ + } while (false) +#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ + do { \ + (void)(ctx); \ + (void)(msg); \ + } while (false) +#define COMMON_INTERCEPTOR_USER_CALLBACK_START() \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_USER_CALLBACK_END() \ + do { \ + } while (false) + +#include "sanitizer_common/sanitizer_common_interceptors.inc" + +//===----------------------------------------------------------------------===// +// Syscall interception +//===----------------------------------------------------------------------===// + +// We want the caller's PC b/c unlike the other function interceptors these +// are separate pre and post functions called around the app's syscall(). + +#define COMMON_SYSCALL_PRE_READ_RANGE(ptr, size) \ + processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, false) + +#define COMMON_SYSCALL_PRE_WRITE_RANGE(ptr, size) \ + do { \ + (void)(ptr); \ + (void)(size); \ + } while (false) + +#define COMMON_SYSCALL_POST_READ_RANGE(ptr, size) \ + do { \ + (void)(ptr); \ + (void)(size); \ + } while (false) + +// The actual amount written is in post, not pre. +#define COMMON_SYSCALL_POST_WRITE_RANGE(ptr, size) \ + processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, true) + +#define COMMON_SYSCALL_ACQUIRE(addr) \ + do { \ + (void)(addr); \ + } while (false) +#define COMMON_SYSCALL_RELEASE(addr) \ + do { \ + (void)(addr); \ + } while (false) +#define COMMON_SYSCALL_FD_CLOSE(fd) \ + do { \ + (void)(fd); \ + } while (false) +#define COMMON_SYSCALL_FD_ACQUIRE(fd) \ + do { \ + (void)(fd); \ + } while (false) +#define COMMON_SYSCALL_FD_RELEASE(fd) \ + do { \ + (void)(fd); \ + } while (false) +#define COMMON_SYSCALL_PRE_FORK() \ + do { \ + } while (false) +#define COMMON_SYSCALL_POST_FORK(res) \ + do { \ + (void)(res); \ + } while (false) + +#include "sanitizer_common/sanitizer_common_syscalls.inc" + +//===----------------------------------------------------------------------===// +// Custom interceptors +//===----------------------------------------------------------------------===// + +// TODO(bruening): move more of these to the common interception pool as they +// are shared with tsan and asan. +// While our other files match LLVM style, here we match sanitizer style as we +// expect to move these to the common pool. + +INTERCEPTOR(char *, strcpy, char *dst, const char *src) { // NOLINT + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strcpy, dst, src); + uptr srclen = internal_strlen(src); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, srclen + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, srclen + 1); + return REAL(strcpy)(dst, src); // NOLINT +} + +INTERCEPTOR(char *, strncpy, char *dst, char *src, uptr n) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strncpy, dst, src, n); + uptr srclen = internal_strnlen(src, n); + uptr copied_size = srclen + 1 > n ? n : srclen + 1; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, copied_size); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, copied_size); + return REAL(strncpy)(dst, src, n); +} + +INTERCEPTOR(int, open, const char *name, int flags, int mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, open, name, flags, mode); + COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); + return REAL(open)(name, flags, mode); +} + +#if SANITIZER_LINUX +INTERCEPTOR(int, open64, const char *name, int flags, int mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, open64, name, flags, mode); + COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); + return REAL(open64)(name, flags, mode); +} +#define ESAN_MAYBE_INTERCEPT_OPEN64 INTERCEPT_FUNCTION(open64) +#else +#define ESAN_MAYBE_INTERCEPT_OPEN64 +#endif + +INTERCEPTOR(int, creat, const char *name, int mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, creat, name, mode); + COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); + return REAL(creat)(name, mode); +} + +#if SANITIZER_LINUX +INTERCEPTOR(int, creat64, const char *name, int mode) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, creat64, name, mode); + COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); + return REAL(creat64)(name, mode); +} +#define ESAN_MAYBE_INTERCEPT_CREAT64 INTERCEPT_FUNCTION(creat64) +#else +#define ESAN_MAYBE_INTERCEPT_CREAT64 +#endif + +INTERCEPTOR(int, unlink, char *path) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, unlink, path); + COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); + return REAL(unlink)(path); +} + +INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, f); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size * nmemb); + return REAL(fread)(ptr, size, nmemb, f); +} + +INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, f); + COMMON_INTERCEPTOR_READ_RANGE(ctx, p, size * nmemb); + return REAL(fwrite)(p, size, nmemb, f); +} + +INTERCEPTOR(int, puts, const char *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, puts, s); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s)); + return REAL(puts)(s); +} + +INTERCEPTOR(int, rmdir, char *path) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, rmdir, path); + COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); + return REAL(rmdir)(path); +} + +//===----------------------------------------------------------------------===// +// Shadow-related interceptors +//===----------------------------------------------------------------------===// + +// These are candidates for sharing with all sanitizers if shadow memory +// support is also standardized. + +INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, + int fd, OFF_T off) { + if (UNLIKELY(REAL(mmap) == nullptr)) { + // With esan init during interceptor init and a static libc preventing + // our early-calloc from triggering, we can end up here before our + // REAL pointer is set up. + return (void *)internal_mmap(addr, sz, prot, flags, fd, off); + } + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); + if (!fixMmapAddr(&addr, sz, flags)) + return (void *)-1; + void *result = REAL(mmap)(addr, sz, prot, flags, fd, off); + return (void *)checkMmapResult((uptr)result, sz); +} + +#if SANITIZER_LINUX +INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, + int fd, OFF64_T off) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); + if (!fixMmapAddr(&addr, sz, flags)) + return (void *)-1; + void *result = REAL(mmap64)(addr, sz, prot, flags, fd, off); + return (void *)checkMmapResult((uptr)result, sz); +} +#define ESAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) +#else +#define ESAN_MAYBE_INTERCEPT_MMAP64 +#endif + +//===----------------------------------------------------------------------===// +// Signal-related interceptors +//===----------------------------------------------------------------------===// + +#if SANITIZER_LINUX +typedef void (*signal_handler_t)(int); +INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, signal, signum, handler); + signal_handler_t result; + if (!processSignal(signum, handler, &result)) + return result; + else + return REAL(signal)(signum, handler); +} +#define ESAN_MAYBE_INTERCEPT_SIGNAL INTERCEPT_FUNCTION(signal) +#else +#error Platform not supported +#define ESAN_MAYBE_INTERCEPT_SIGNAL +#endif + +#if SANITIZER_LINUX +DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, + struct sigaction *oldact) +INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, + struct sigaction *oldact) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigaction, signum, act, oldact); + if (!processSigaction(signum, act, oldact)) + return 0; + else + return REAL(sigaction)(signum, act, oldact); +} + +// This is required to properly use internal_sigaction. +namespace __sanitizer { +int real_sigaction(int signum, const void *act, void *oldact) { + if (REAL(sigaction) == nullptr) { + // With an instrumented allocator, this is called during interceptor init + // and we need a raw syscall solution. + return internal_sigaction_syscall(signum, act, oldact); + } + return REAL(sigaction)(signum, (const struct sigaction *)act, + (struct sigaction *)oldact); +} +} // namespace __sanitizer + +#define ESAN_MAYBE_INTERCEPT_SIGACTION INTERCEPT_FUNCTION(sigaction) +#else +#error Platform not supported +#define ESAN_MAYBE_INTERCEPT_SIGACTION +#endif + +#if SANITIZER_LINUX +INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); + int res = 0; + if (processSigprocmask(how, set, oldset)) + res = REAL(sigprocmask)(how, set, oldset); + if (!res && oldset) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); + return res; +} +#define ESAN_MAYBE_INTERCEPT_SIGPROCMASK INTERCEPT_FUNCTION(sigprocmask) +#else +#define ESAN_MAYBE_INTERCEPT_SIGPROCMASK +#endif + +#if !SANITIZER_WINDOWS +INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_sigmask, how, set, oldset); + int res = 0; + if (processSigprocmask(how, set, oldset)) + res = REAL(sigprocmask)(how, set, oldset); + if (!res && oldset) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); + return res; +} +#define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK INTERCEPT_FUNCTION(pthread_sigmask) +#else +#define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK +#endif + +//===----------------------------------------------------------------------===// +// Malloc interceptors +//===----------------------------------------------------------------------===// + +static char early_alloc_buf[128]; +static bool used_early_alloc_buf; + +static void *handleEarlyAlloc(uptr size) { + // If esan is initialized during an interceptor (which happens with some + // tcmalloc implementations that call pthread_mutex_lock), the call from + // dlsym to calloc will deadlock. There is only one such calloc (dlsym + // allocates a single pthread key), so we work around it by using a + // static buffer for the calloc request. The loader currently needs + // 32 bytes but we size at 128 to allow for future changes. + // This solution will also allow us to deliberately intercept malloc & family + // in the future (to perform tool actions on each allocation, without + // replacing the allocator), as it also solves the problem of intercepting + // calloc when it will itself be called before its REAL pointer is + // initialized. + CHECK(!used_early_alloc_buf && size < sizeof(early_alloc_buf)); + // We do not handle multiple threads here. This only happens at process init + // time, and while it's possible for a shared library to create early threads + // that race here, we consider that to be a corner case extreme enough that + // it's not worth the effort to handle. + used_early_alloc_buf = true; + return (void *)early_alloc_buf; +} + +INTERCEPTOR(void*, calloc, uptr size, uptr n) { + if (EsanDuringInit && REAL(calloc) == nullptr) + return handleEarlyAlloc(size * n); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, calloc, size, n); + void *res = REAL(calloc)(size, n); + // The memory is zeroed and thus is all written. + COMMON_INTERCEPTOR_WRITE_RANGE(nullptr, (uptr)res, size * n); + return res; +} + +INTERCEPTOR(void, free, void *p) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, free, p); + if (p == (void *)early_alloc_buf) { + // We expect just a singleton use but we clear this for cleanliness. + used_early_alloc_buf = false; + return; + } + REAL(free)(p); +} + +namespace __esan { + +void initializeInterceptors() { + InitializeCommonInterceptors(); + + INTERCEPT_FUNCTION(strcpy); // NOLINT + INTERCEPT_FUNCTION(strncpy); + + INTERCEPT_FUNCTION(open); + ESAN_MAYBE_INTERCEPT_OPEN64; + INTERCEPT_FUNCTION(creat); + ESAN_MAYBE_INTERCEPT_CREAT64; + INTERCEPT_FUNCTION(unlink); + INTERCEPT_FUNCTION(fread); + INTERCEPT_FUNCTION(fwrite); + INTERCEPT_FUNCTION(puts); + INTERCEPT_FUNCTION(rmdir); + + INTERCEPT_FUNCTION(mmap); + ESAN_MAYBE_INTERCEPT_MMAP64; + + ESAN_MAYBE_INTERCEPT_SIGNAL; + ESAN_MAYBE_INTERCEPT_SIGACTION; + ESAN_MAYBE_INTERCEPT_SIGPROCMASK; + ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK; + + INTERCEPT_FUNCTION(calloc); + INTERCEPT_FUNCTION(free); + + // TODO(bruening): intercept routines that other sanitizers intercept that + // are not in the common pool or here yet, ideally by adding to the common + // pool. Examples include wcslen and bcopy. + + // TODO(bruening): there are many more libc routines that read or write data + // structures that no sanitizer is intercepting: sigaction, strtol, etc. +} + +} // namespace __esan diff --git a/contrib/compiler-rt/lib/esan/esan_interface.cpp b/contrib/compiler-rt/lib/esan/esan_interface.cpp new file mode 100644 index 000000000000..43b3dff86f77 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_interface.cpp @@ -0,0 +1,122 @@ +//===-- esan_interface.cpp ------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +//===----------------------------------------------------------------------===// + +#include "esan_interface_internal.h" +#include "esan.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +using namespace __esan; // NOLINT + +void __esan_init(ToolType Tool, void *Ptr) { + if (Tool != __esan_which_tool) { + Printf("ERROR: tool mismatch: %d vs %d\n", Tool, __esan_which_tool); + Die(); + } + initializeLibrary(Tool); + processCompilationUnitInit(Ptr); +} + +void __esan_exit(void *Ptr) { + processCompilationUnitExit(Ptr); +} + +void __esan_aligned_load1(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, false); +} + +void __esan_aligned_load2(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false); +} + +void __esan_aligned_load4(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false); +} + +void __esan_aligned_load8(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false); +} + +void __esan_aligned_load16(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false); +} + +void __esan_aligned_store1(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, true); +} + +void __esan_aligned_store2(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true); +} + +void __esan_aligned_store4(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true); +} + +void __esan_aligned_store8(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true); +} + +void __esan_aligned_store16(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true); +} + +void __esan_unaligned_load2(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false); +} + +void __esan_unaligned_load4(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false); +} + +void __esan_unaligned_load8(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false); +} + +void __esan_unaligned_load16(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false); +} + +void __esan_unaligned_store2(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true); +} + +void __esan_unaligned_store4(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true); +} + +void __esan_unaligned_store8(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true); +} + +void __esan_unaligned_store16(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true); +} + +void __esan_unaligned_loadN(void *Addr, uptr Size) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, false); +} + +void __esan_unaligned_storeN(void *Addr, uptr Size) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, true); +} + +// Public interface: +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE void __esan_report() { + reportResults(); +} + +SANITIZER_INTERFACE_ATTRIBUTE unsigned int __esan_get_sample_count() { + return getSampleCount(); +} +} // extern "C" diff --git a/contrib/compiler-rt/lib/esan/esan_interface_internal.h b/contrib/compiler-rt/lib/esan/esan_interface_internal.h new file mode 100644 index 000000000000..3b915d03e07a --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_interface_internal.h @@ -0,0 +1,80 @@ +//===-- esan_interface_internal.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Calls to the functions declared in this header will be inserted by +// the instrumentation module. +//===----------------------------------------------------------------------===// + +#ifndef ESAN_INTERFACE_INTERNAL_H +#define ESAN_INTERFACE_INTERNAL_H + +#include + +// This header should NOT include any other headers. +// All functions in this header are extern "C" and start with __esan_. + +extern "C" { + +// This should be kept consistent with LLVM's EfficiencySanitizerOptions. +// The value is passed as a 32-bit integer by the compiler. +typedef enum Type : u32 { + ESAN_None = 0, + ESAN_CacheFrag, + ESAN_WorkingSet, + ESAN_Max, +} ToolType; + +// To handle interceptors that invoke instrumented code prior to +// __esan_init() being called, the instrumentation module creates this +// global variable specifying the tool. +extern ToolType __esan_which_tool; + +// This function should be called at the very beginning of the process, +// before any instrumented code is executed and before any call to malloc. +SANITIZER_INTERFACE_ATTRIBUTE void __esan_init(ToolType Tool, void *Ptr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_exit(void *Ptr); + +// The instrumentation module will insert a call to one of these routines prior +// to each load and store instruction for which we do not have "fastpath" +// inlined instrumentation. These calls constitute the "slowpath" for our +// tools. We have separate routines for each type of memory access to enable +// targeted optimization. +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load1(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load2(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load4(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load8(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load16(void *Addr); + +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store1(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store2(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store4(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store8(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store16(void *Addr); + +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load2(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load4(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load8(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load16(void *Addr); + +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store2(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store4(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store8(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store16(void *Addr); + +// These cover unusually-sized accesses. +SANITIZER_INTERFACE_ATTRIBUTE +void __esan_unaligned_loadN(void *Addr, uptr Size); +SANITIZER_INTERFACE_ATTRIBUTE +void __esan_unaligned_storeN(void *Addr, uptr Size); + +} // extern "C" + +#endif // ESAN_INTERFACE_INTERNAL_H diff --git a/contrib/compiler-rt/lib/esan/esan_linux.cpp b/contrib/compiler-rt/lib/esan/esan_linux.cpp new file mode 100644 index 000000000000..aa961b66116b --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_linux.cpp @@ -0,0 +1,83 @@ +//===-- esan.cpp ----------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Linux-specific code for the Esan run-time. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_FREEBSD || SANITIZER_LINUX + +#include "esan.h" +#include "esan_shadow.h" +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_common.h" +#include +#include + +namespace __esan { + +void verifyAddressSpace() { +#if SANITIZER_LINUX && defined(__x86_64__) + // The kernel determines its mmap base from the stack size limit. + // Our Linux 64-bit shadow mapping assumes the stack limit is less than a + // terabyte, which keeps the mmap region above 0x7e00'. + uptr StackLimit = GetStackSizeLimitInBytes(); + if (StackSizeIsUnlimited() || StackLimit > MaxStackSize) { + VReport(1, "The stack size limit is beyond the maximum supported.\n" + "Re-execing with a stack size below 1TB.\n"); + SetStackSizeLimitInBytes(MaxStackSize); + ReExec(); + } +#endif +} + +static bool liesWithinSingleAppRegion(uptr Start, SIZE_T Size) { + uptr AppStart, AppEnd; + for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { + if (Start >= AppStart && Start + Size - 1 <= AppEnd) { + return true; + } + } + return false; +} + +bool fixMmapAddr(void **Addr, SIZE_T Size, int Flags) { + if (*Addr) { + if (!liesWithinSingleAppRegion((uptr)*Addr, Size)) { + VPrintf(1, "mmap conflict: [%p-%p) is not in an app region\n", + *Addr, (uptr)*Addr + Size); + if (Flags & MAP_FIXED) { + errno = EINVAL; + return false; + } else { + *Addr = 0; + } + } + } + return true; +} + +uptr checkMmapResult(uptr Addr, SIZE_T Size) { + if ((void *)Addr == MAP_FAILED) + return Addr; + if (!liesWithinSingleAppRegion(Addr, Size)) { + // FIXME: attempt to dynamically add this as an app region if it + // fits our shadow criteria. + // We could also try to remap somewhere else. + Printf("ERROR: unsupported mapping at [%p-%p)\n", Addr, Addr+Size); + Die(); + } + return Addr; +} + +} // namespace __esan + +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/contrib/compiler-rt/lib/esan/esan_shadow.h b/contrib/compiler-rt/lib/esan/esan_shadow.h new file mode 100644 index 000000000000..f8f154ef7cca --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_shadow.h @@ -0,0 +1,203 @@ +//===-- esan_shadow.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Shadow memory mappings for the esan run-time. +//===----------------------------------------------------------------------===// + +#ifndef ESAN_SHADOW_H +#define ESAN_SHADOW_H + +#include + +#if SANITIZER_WORDSIZE != 64 +#error Only 64-bit is supported +#endif + +namespace __esan { + +#if SANITIZER_LINUX && defined(__x86_64__) +// Linux x86_64 +// +// Application memory falls into these 5 regions (ignoring the corner case +// of PIE with a non-zero PT_LOAD base): +// +// [0x00000000'00000000, 0x00000100'00000000) non-PIE + heap +// [0x00005500'00000000, 0x00005700'00000000) PIE +// [0x00007e00'00000000, 0x00007fff'ff600000) libraries + stack, part 1 +// [0x00007fff'ff601000, 0x00008000'00000000) libraries + stack, part 2 +// [0xffffffff'ff600000, 0xffffffff'ff601000) vsyscall +// +// Although we can ignore the vsyscall for the most part as there are few data +// references there (other sanitizers ignore it), we enforce a gap inside the +// library region to distinguish the vsyscall's shadow, considering this gap to +// be an invalid app region. +// We disallow application memory outside of those 5 regions. +// Our regions assume that the stack rlimit is less than a terabyte (otherwise +// the Linux kernel's default mmap region drops below 0x7e00'), which we enforce +// at init time (we can support larger and unlimited sizes for shadow +// scaledowns, but it is difficult for 1:1 mappings). +// +// Our shadow memory is scaled from a 1:1 mapping and supports a scale +// specified at library initialization time that can be any power-of-2 +// scaledown (1x, 2x, 4x, 8x, 16x, etc.). +// +// We model our shadow memory after Umbra, a library used by the Dr. Memory +// tool: https://github.com/DynamoRIO/drmemory/blob/master/umbra/umbra_x64.c. +// We use Umbra's scheme as it was designed to support different +// offsets, it supports two different shadow mappings (which we may want to +// use for future tools), and it ensures that the shadow of a shadow will +// not overlap either shadow memory or application memory. +// +// This formula translates from application memory to shadow memory: +// +// shadow(app) = ((app & 0x00000fff'ffffffff) + offset) >> scale +// +// Where the offset for 1:1 is 0x00001300'00000000. For other scales, the +// offset is shifted left by the scale, except for scales of 1 and 2 where +// it must be tweaked in order to pass the double-shadow test +// (see the "shadow(shadow)" comments below): +// scale == 0: 0x00001300'000000000 +// scale == 1: 0x00002200'000000000 +// scale == 2: 0x00004400'000000000 +// scale >= 3: (0x00001300'000000000 << scale) +// +// Do not pass in the open-ended end value to the formula as it will fail. +// +// The resulting shadow memory regions for a 0 scaling are: +// +// [0x00001300'00000000, 0x00001400'00000000) +// [0x00001800'00000000, 0x00001a00'00000000) +// [0x00002100'00000000, 0x000022ff'ff600000) +// [0x000022ff'ff601000, 0x00002300'00000000) +// [0x000022ff'ff600000, 0x000022ff'ff601000] +// +// We also want to ensure that a wild access by the application into the shadow +// regions will not corrupt our own shadow memory. shadow(shadow) ends up +// disjoint from shadow(app): +// +// [0x00001600'00000000, 0x00001700'00000000) +// [0x00001b00'00000000, 0x00001d00'00000000) +// [0x00001400'00000000, 0x000015ff'ff600000] +// [0x000015ff'ff601000, 0x00001600'00000000] +// [0x000015ff'ff600000, 0x000015ff'ff601000] + +struct ApplicationRegion { + uptr Start; + uptr End; + bool ShadowMergedWithPrev; +}; + +static const struct ApplicationRegion AppRegions[] = { + {0x0000000000000000ull, 0x0000010000000000u, false}, + {0x0000550000000000u, 0x0000570000000000u, false}, + // We make one shadow mapping to hold the shadow regions for all 3 of these + // app regions, as the mappings interleave, and the gap between the 3rd and + // 4th scales down below a page. + {0x00007e0000000000u, 0x00007fffff600000u, false}, + {0x00007fffff601000u, 0x0000800000000000u, true}, + {0xffffffffff600000u, 0xffffffffff601000u, true}, +}; +static const u32 NumAppRegions = sizeof(AppRegions)/sizeof(AppRegions[0]); + +// See the comment above: we do not currently support a stack size rlimit +// equal to or larger than 1TB. +static const uptr MaxStackSize = (1ULL << 40) - 4096; + +class ShadowMapping { +public: + static const uptr Mask = 0x00000fffffffffffu; + // The scale and offset vary by tool. + uptr Scale; + uptr Offset; + void initialize(uptr ShadowScale) { + static const uptr OffsetArray[3] = { + 0x0000130000000000u, + 0x0000220000000000u, + 0x0000440000000000u, + }; + Scale = ShadowScale; + if (Scale <= 2) + Offset = OffsetArray[Scale]; + else + Offset = OffsetArray[0] << Scale; + } +}; +extern ShadowMapping Mapping; +#else +// We'll want to use templatized functions over the ShadowMapping once +// we support more platforms. +#error Platform not supported +#endif + +static inline bool getAppRegion(u32 i, uptr *Start, uptr *End) { + if (i >= NumAppRegions) + return false; + *Start = AppRegions[i].Start; + *End = AppRegions[i].End; + return true; +} + +ALWAYS_INLINE +bool isAppMem(uptr Mem) { + for (u32 i = 0; i < NumAppRegions; ++i) { + if (Mem >= AppRegions[i].Start && Mem < AppRegions[i].End) + return true; + } + return false; +} + +ALWAYS_INLINE +uptr appToShadow(uptr App) { + return (((App & ShadowMapping::Mask) + Mapping.Offset) >> Mapping.Scale); +} + +static inline bool getShadowRegion(u32 i, uptr *Start, uptr *End) { + if (i >= NumAppRegions) + return false; + u32 UnmergedShadowCount = 0; + u32 AppIdx; + for (AppIdx = 0; AppIdx < NumAppRegions; ++AppIdx) { + if (!AppRegions[AppIdx].ShadowMergedWithPrev) { + if (UnmergedShadowCount == i) + break; + UnmergedShadowCount++; + } + } + if (AppIdx >= NumAppRegions || UnmergedShadowCount != i) + return false; + *Start = appToShadow(AppRegions[AppIdx].Start); + // The formula fails for the end itself. + *End = appToShadow(AppRegions[AppIdx].End - 1) + 1; + // Merge with adjacent shadow regions: + for (++AppIdx; AppIdx < NumAppRegions; ++AppIdx) { + if (!AppRegions[AppIdx].ShadowMergedWithPrev) + break; + *Start = Min(*Start, appToShadow(AppRegions[AppIdx].Start)); + *End = Max(*End, appToShadow(AppRegions[AppIdx].End - 1) + 1); + } + return true; +} + +ALWAYS_INLINE +bool isShadowMem(uptr Mem) { + // We assume this is not used on any critical performance path and so there's + // no need to hardcode the mapping results. + for (uptr i = 0; i < NumAppRegions; ++i) { + if (Mem >= appToShadow(AppRegions[i].Start) && + Mem < appToShadow(AppRegions[i].End - 1) + 1) + return true; + } + return false; +} + +} // namespace __esan + +#endif /* ESAN_SHADOW_H */ diff --git a/contrib/compiler-rt/lib/esan/esan_sideline.h b/contrib/compiler-rt/lib/esan/esan_sideline.h new file mode 100644 index 000000000000..aa3fae1db318 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_sideline.h @@ -0,0 +1,61 @@ +//===-- esan_sideline.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Esan sideline thread support. +//===----------------------------------------------------------------------===// + +#ifndef ESAN_SIDELINE_H +#define ESAN_SIDELINE_H + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __esan { + +typedef void (*SidelineFunc)(void *Arg); + +// Currently only one sideline thread is supported. +// It calls the SidelineFunc passed to launchThread once on each sample at the +// given frequency in real time (i.e., wall clock time). +class SidelineThread { +public: + // We cannot initialize any fields in the constructor as it will be called + // *after* launchThread for a static instance, as esan.module_ctor is called + // before static initializers. + SidelineThread() {} + ~SidelineThread() {} + + // To simplify declaration in sanitizer code where we want to avoid + // heap allocations, the constructor and destructor do nothing and + // launchThread and joinThread do the real work. + // They should each be called just once. + bool launchThread(SidelineFunc takeSample, void *Arg, u32 FreqMilliSec); + bool joinThread(); + + // Must be called from the sideline thread itself. + bool adjustTimer(u32 FreqMilliSec); + +private: + static int runSideline(void *Arg); + static void registerSignal(int SigNum); + static void handleSidelineSignal(int SigNum, void *SigInfo, void *Ctx); + + char *Stack; + SidelineFunc sampleFunc; + void *FuncArg; + u32 Freq; + uptr SidelineId; + atomic_uintptr_t SidelineExit; +}; + +} // namespace __esan + +#endif // ESAN_SIDELINE_H diff --git a/contrib/compiler-rt/lib/esan/esan_sideline_linux.cpp b/contrib/compiler-rt/lib/esan/esan_sideline_linux.cpp new file mode 100644 index 000000000000..d04f5909d6a2 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/esan_sideline_linux.cpp @@ -0,0 +1,177 @@ +//===-- esan_sideline_linux.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Support for a separate or "sideline" tool thread on Linux. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_LINUX + +#include "esan_sideline.h" +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_linux.h" +#include +#include +#include +#include +#include +#include +#include + +namespace __esan { + +static const int SigAltStackSize = 4*1024; +static const int SidelineStackSize = 4*1024; +static const uptr SidelineIdUninitialized = 1; + +// FIXME: we'll need some kind of TLS (can we trust that a pthread key will +// work in our non-POSIX thread?) to access our data in our signal handler +// with multiple sideline threads. For now we assume there is only one +// sideline thread and we use a dirty solution of a global var. +static SidelineThread *TheThread; + +// We aren't passing SA_NODEFER so the same signal is blocked while here. +void SidelineThread::handleSidelineSignal(int SigNum, void *SigInfo, + void *Ctx) { + VPrintf(3, "Sideline signal %d\n", SigNum); + CHECK_EQ(SigNum, SIGALRM); + // See above about needing TLS to avoid this global var. + SidelineThread *Thread = TheThread; + if (atomic_load(&Thread->SidelineExit, memory_order_relaxed) != 0) + return; + Thread->sampleFunc(Thread->FuncArg); +} + +void SidelineThread::registerSignal(int SigNum) { + __sanitizer_sigaction SigAct; + internal_memset(&SigAct, 0, sizeof(SigAct)); + SigAct.sigaction = handleSidelineSignal; + // We do not pass SA_NODEFER as we want to block the same signal. + SigAct.sa_flags = SA_ONSTACK | SA_SIGINFO; + int Res = internal_sigaction(SigNum, &SigAct, nullptr); + CHECK_EQ(Res, 0); +} + +int SidelineThread::runSideline(void *Arg) { + VPrintf(1, "Sideline thread starting\n"); + SidelineThread *Thread = static_cast(Arg); + + // If the parent dies, we want to exit also. + internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); + + // Set up a signal handler on an alternate stack for safety. + InternalScopedBuffer StackMap(SigAltStackSize); + struct sigaltstack SigAltStack; + SigAltStack.ss_sp = StackMap.data(); + SigAltStack.ss_size = SigAltStackSize; + SigAltStack.ss_flags = 0; + internal_sigaltstack(&SigAltStack, nullptr); + + // We inherit the signal mask from the app thread. In case + // we weren't created at init time, we ensure the mask is empty. + __sanitizer_sigset_t SigSet; + internal_sigfillset(&SigSet); + int Res = internal_sigprocmask(SIG_UNBLOCK, &SigSet, nullptr); + CHECK_EQ(Res, 0); + + registerSignal(SIGALRM); + + bool TimerSuccess = Thread->adjustTimer(Thread->Freq); + CHECK(TimerSuccess); + + // We loop, doing nothing but handling itimer signals. + while (atomic_load(&TheThread->SidelineExit, memory_order_relaxed) == 0) + sched_yield(); + + if (!Thread->adjustTimer(0)) + VPrintf(1, "Failed to disable timer\n"); + + VPrintf(1, "Sideline thread exiting\n"); + return 0; +} + +bool SidelineThread::launchThread(SidelineFunc takeSample, void *Arg, + u32 FreqMilliSec) { + // This can only be called once. However, we can't clear a field in + // the constructor and check for that here as the constructor for + // a static instance is called *after* our module_ctor and thus after + // this routine! Thus we rely on the TheThread check below. + CHECK(TheThread == nullptr); // Only one sideline thread is supported. + TheThread = this; + sampleFunc = takeSample; + FuncArg = Arg; + Freq = FreqMilliSec; + atomic_store(&SidelineExit, 0, memory_order_relaxed); + + // We do without a guard page. + Stack = static_cast(MmapOrDie(SidelineStackSize, "SidelineStack")); + // We need to handle the return value from internal_clone() not having been + // assigned yet (for our CHECK in adjustTimer()) so we ensure this has a + // sentinel value. + SidelineId = SidelineIdUninitialized; + // By omitting CLONE_THREAD, the child is in its own thread group and will not + // receive any of the application's signals. + SidelineId = internal_clone( + runSideline, Stack + SidelineStackSize, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED, + this, nullptr /* parent_tidptr */, + nullptr /* newtls */, nullptr /* child_tidptr */); + int ErrCode; + if (internal_iserror(SidelineId, &ErrCode)) { + Printf("FATAL: EfficiencySanitizer failed to spawn a thread (code %d).\n", + ErrCode); + Die(); + return false; // Not reached. + } + return true; +} + +bool SidelineThread::joinThread() { + VPrintf(1, "Joining sideline thread\n"); + bool Res = true; + atomic_store(&SidelineExit, 1, memory_order_relaxed); + while (true) { + uptr Status = internal_waitpid(SidelineId, nullptr, __WALL); + int ErrCode; + if (!internal_iserror(Status, &ErrCode)) + break; + if (ErrCode == EINTR) + continue; + VPrintf(1, "Failed to join sideline thread (errno %d)\n", ErrCode); + Res = false; + break; + } + UnmapOrDie(Stack, SidelineStackSize); + return Res; +} + +// Must be called from the sideline thread itself. +bool SidelineThread::adjustTimer(u32 FreqMilliSec) { + // The return value of internal_clone() may not have been assigned yet: + CHECK(internal_getpid() == SidelineId || + SidelineId == SidelineIdUninitialized); + Freq = FreqMilliSec; + struct itimerval TimerVal; + TimerVal.it_interval.tv_sec = (time_t) Freq / 1000; + TimerVal.it_interval.tv_usec = (time_t) (Freq % 1000) * 1000; + TimerVal.it_value.tv_sec = (time_t) Freq / 1000; + TimerVal.it_value.tv_usec = (time_t) (Freq % 1000) * 1000; + // As we're in a different thread group, we cannot use either + // ITIMER_PROF or ITIMER_VIRTUAL without taking up scheduled + // time ourselves: thus we must use real time. + int Res = setitimer(ITIMER_REAL, &TimerVal, nullptr); + return (Res == 0); +} + +} // namespace __esan + +#endif // SANITIZER_LINUX diff --git a/contrib/compiler-rt/lib/esan/working_set.cpp b/contrib/compiler-rt/lib/esan/working_set.cpp new file mode 100644 index 000000000000..f39111993c33 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/working_set.cpp @@ -0,0 +1,279 @@ +//===-- working_set.cpp ---------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// This file contains working-set-specific code. +//===----------------------------------------------------------------------===// + +#include "working_set.h" +#include "esan.h" +#include "esan_circular_buffer.h" +#include "esan_flags.h" +#include "esan_shadow.h" +#include "esan_sideline.h" +#include "sanitizer_common/sanitizer_procmaps.h" + +// We shadow every cache line of app memory with one shadow byte. +// - The highest bit of each shadow byte indicates whether the corresponding +// cache line has ever been accessed. +// - The lowest bit of each shadow byte indicates whether the corresponding +// cache line was accessed since the last sample. +// - The other bits are used for working set snapshots at successively +// lower frequencies, each bit to the left from the lowest bit stepping +// down the frequency by 2 to the power of getFlags()->snapshot_step. +// Thus we have something like this: +// Bit 0: Since last sample +// Bit 1: Since last 2^2 samples +// Bit 2: Since last 2^4 samples +// Bit 3: ... +// Bit 7: Ever accessed. +// We live with races in accessing each shadow byte. +typedef unsigned char byte; + +namespace __esan { + +// Our shadow memory assumes that the line size is 64. +static const u32 CacheLineSize = 64; + +// See the shadow byte layout description above. +static const u32 TotalWorkingSetBitIdx = 7; +// We accumulate to the left until we hit this bit. +// We don't need to accumulate to the final bit as it's set on each ref +// by the compiler instrumentation. +static const u32 MaxAccumBitIdx = 6; +static const u32 CurWorkingSetBitIdx = 0; +static const byte ShadowAccessedVal = + (1 << TotalWorkingSetBitIdx) | (1 << CurWorkingSetBitIdx); + +static SidelineThread Thread; +// If we use real-time-based timer samples this won't overflow in any realistic +// scenario, but if we switch to some other unit (such as memory accesses) we +// may want to consider a 64-bit int. +static u32 SnapshotNum; + +// We store the wset size for each of 8 different sampling frequencies. +static const u32 NumFreq = 8; // One for each bit of our shadow bytes. +// We cannot use static objects as the global destructor is called +// prior to our finalize routine. +// These are each circular buffers, sized up front. +CircularBuffer SizePerFreq[NumFreq]; +// We cannot rely on static initializers (they may run too late) but +// we record the size here for clarity: +u32 CircularBufferSizes[NumFreq] = { + // These are each mmap-ed so our minimum is one page. + 32*1024, + 16*1024, + 8*1024, + 4*1024, + 4*1024, + 4*1024, + 4*1024, + 4*1024, +}; + +void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size, + bool IsWrite) { + if (Size == 0) + return; + SIZE_T I = 0; + uptr LineSize = getFlags()->cache_line_size; + // As Addr+Size could overflow at the top of a 32-bit address space, + // we avoid the simpler formula that rounds the start and end. + SIZE_T NumLines = Size / LineSize + + // Add any extra at the start or end adding on an extra line: + (LineSize - 1 + Addr % LineSize + Size % LineSize) / LineSize; + byte *Shadow = (byte *)appToShadow(Addr); + // Write shadow bytes until we're word-aligned. + while (I < NumLines && (uptr)Shadow % 4 != 0) { + if ((*Shadow & ShadowAccessedVal) != ShadowAccessedVal) + *Shadow |= ShadowAccessedVal; + ++Shadow; + ++I; + } + // Write whole shadow words at a time. + // Using a word-stride loop improves the runtime of a microbenchmark of + // memset calls by 10%. + u32 WordValue = ShadowAccessedVal | ShadowAccessedVal << 8 | + ShadowAccessedVal << 16 | ShadowAccessedVal << 24; + while (I + 4 <= NumLines) { + if ((*(u32*)Shadow & WordValue) != WordValue) + *(u32*)Shadow |= WordValue; + Shadow += 4; + I += 4; + } + // Write any trailing shadow bytes. + while (I < NumLines) { + if ((*Shadow & ShadowAccessedVal) != ShadowAccessedVal) + *Shadow |= ShadowAccessedVal; + ++Shadow; + ++I; + } +} + +// This routine will word-align ShadowStart and ShadowEnd prior to scanning. +// It does *not* clear for BitIdx==TotalWorkingSetBitIdx, as that top bit +// measures the access during the entire execution and should never be cleared. +static u32 countAndClearShadowValues(u32 BitIdx, uptr ShadowStart, + uptr ShadowEnd) { + u32 WorkingSetSize = 0; + u32 ByteValue = 0x1 << BitIdx; + u32 WordValue = ByteValue | ByteValue << 8 | ByteValue << 16 | + ByteValue << 24; + // Get word aligned start. + ShadowStart = RoundDownTo(ShadowStart, sizeof(u32)); + bool Accum = getFlags()->record_snapshots && BitIdx < MaxAccumBitIdx; + // Do not clear the bit that measures access during the entire execution. + bool Clear = BitIdx < TotalWorkingSetBitIdx; + for (u32 *Ptr = (u32 *)ShadowStart; Ptr < (u32 *)ShadowEnd; ++Ptr) { + if ((*Ptr & WordValue) != 0) { + byte *BytePtr = (byte *)Ptr; + for (u32 j = 0; j < sizeof(u32); ++j) { + if (BytePtr[j] & ByteValue) { + ++WorkingSetSize; + if (Accum) { + // Accumulate to the lower-frequency bit to the left. + BytePtr[j] |= (ByteValue << 1); + } + } + } + if (Clear) { + // Clear this bit from every shadow byte. + *Ptr &= ~WordValue; + } + } + } + return WorkingSetSize; +} + +// Scan shadow memory to calculate the number of cache lines being accessed, +// i.e., the number of non-zero bits indexed by BitIdx in each shadow byte. +// We also clear the lowest bits (most recent working set snapshot). +// We do *not* clear for BitIdx==TotalWorkingSetBitIdx, as that top bit +// measures the access during the entire execution and should never be cleared. +static u32 computeWorkingSizeAndReset(u32 BitIdx) { + u32 WorkingSetSize = 0; + MemoryMappingLayout MemIter(true/*cache*/); + uptr Start, End, Prot; + while (MemIter.Next(&Start, &End, nullptr/*offs*/, nullptr/*file*/, + 0/*file size*/, &Prot)) { + VPrintf(4, "%s: considering %p-%p app=%d shadow=%d prot=%u\n", + __FUNCTION__, Start, End, Prot, isAppMem(Start), + isShadowMem(Start)); + if (isShadowMem(Start) && (Prot & MemoryMappingLayout::kProtectionWrite)) { + VPrintf(3, "%s: walking %p-%p\n", __FUNCTION__, Start, End); + WorkingSetSize += countAndClearShadowValues(BitIdx, Start, End); + } + } + return WorkingSetSize; +} + +// This is invoked from a signal handler but in a sideline thread doing nothing +// else so it is a little less fragile than a typical signal handler. +static void takeSample(void *Arg) { + u32 BitIdx = CurWorkingSetBitIdx; + u32 Freq = 1; + ++SnapshotNum; // Simpler to skip 0 whose mod matches everything. + while (BitIdx <= MaxAccumBitIdx && (SnapshotNum % Freq) == 0) { + u32 NumLines = computeWorkingSizeAndReset(BitIdx); + VReport(1, "%s: snapshot #%5d bit %d freq %4d: %8u\n", SanitizerToolName, + SnapshotNum, BitIdx, Freq, NumLines); + SizePerFreq[BitIdx].push_back(NumLines); + Freq = Freq << getFlags()->snapshot_step; + BitIdx++; + } +} + +unsigned int getSampleCountWorkingSet() +{ + return SnapshotNum; +} + +// Initialization that must be done before any instrumented code is executed. +void initializeShadowWorkingSet() { + CHECK(getFlags()->cache_line_size == CacheLineSize); + registerMemoryFaultHandler(); +} + +void initializeWorkingSet() { + if (getFlags()->record_snapshots) { + for (u32 i = 0; i < NumFreq; ++i) + SizePerFreq[i].initialize(CircularBufferSizes[i]); + Thread.launchThread(takeSample, nullptr, getFlags()->sample_freq); + } +} + +static u32 getPeriodForPrinting(u32 MilliSec, const char *&Unit) { + if (MilliSec > 600000) { + Unit = "min"; + return MilliSec / 60000; + } else if (MilliSec > 10000) { + Unit = "sec"; + return MilliSec / 1000; + } else { + Unit = "ms"; + return MilliSec; + } +} + +static u32 getSizeForPrinting(u32 NumOfCachelines, const char *&Unit) { + // We need a constant to avoid software divide support: + static const u32 KilobyteCachelines = (0x1 << 10) / CacheLineSize; + static const u32 MegabyteCachelines = KilobyteCachelines << 10; + + if (NumOfCachelines > 10 * MegabyteCachelines) { + Unit = "MB"; + return NumOfCachelines / MegabyteCachelines; + } else if (NumOfCachelines > 10 * KilobyteCachelines) { + Unit = "KB"; + return NumOfCachelines / KilobyteCachelines; + } else { + Unit = "Bytes"; + return NumOfCachelines * CacheLineSize; + } +} + +void reportWorkingSet() { + const char *Unit; + if (getFlags()->record_snapshots) { + u32 Freq = 1; + Report(" Total number of samples: %u\n", SnapshotNum); + for (u32 i = 0; i < NumFreq; ++i) { + u32 Time = getPeriodForPrinting(getFlags()->sample_freq*Freq, Unit); + Report(" Samples array #%d at period %u %s\n", i, Time, Unit); + // FIXME: report whether we wrapped around and thus whether we + // have data on the whole run or just the last N samples. + for (u32 j = 0; j < SizePerFreq[i].size(); ++j) { + u32 Size = getSizeForPrinting(SizePerFreq[i][j], Unit); + Report("#%4d: %8u %s (%9u cache lines)\n", j, Size, Unit, + SizePerFreq[i][j]); + } + Freq = Freq << getFlags()->snapshot_step; + } + } + + // Get the working set size for the entire execution. + u32 NumOfCachelines = computeWorkingSizeAndReset(TotalWorkingSetBitIdx); + u32 Size = getSizeForPrinting(NumOfCachelines, Unit); + Report(" %s: the total working set size: %u %s (%u cache lines)\n", + SanitizerToolName, Size, Unit, NumOfCachelines); +} + +int finalizeWorkingSet() { + if (getFlags()->record_snapshots) + Thread.joinThread(); + reportWorkingSet(); + if (getFlags()->record_snapshots) { + for (u32 i = 0; i < NumFreq; ++i) + SizePerFreq[i].free(); + } + return 0; +} + +} // namespace __esan diff --git a/contrib/compiler-rt/lib/esan/working_set.h b/contrib/compiler-rt/lib/esan/working_set.h new file mode 100644 index 000000000000..6a976c3f9b22 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/working_set.h @@ -0,0 +1,40 @@ +//===-- working_set.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Header for working-set-specific code. +//===----------------------------------------------------------------------===// + +#ifndef WORKING_SET_H +#define WORKING_SET_H + +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __esan { + +void initializeWorkingSet(); +void initializeShadowWorkingSet(); +int finalizeWorkingSet(); +void reportWorkingSet(); +unsigned int getSampleCountWorkingSet(); +void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size, + bool IsWrite); + +// Platform-dependent. +void registerMemoryFaultHandler(); +bool processWorkingSetSignal(int SigNum, void (*Handler)(int), + void (**Result)(int)); +bool processWorkingSetSigaction(int SigNum, const void *Act, void *OldAct); +bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet); + +} // namespace __esan + +#endif // WORKING_SET_H diff --git a/contrib/compiler-rt/lib/esan/working_set_posix.cpp b/contrib/compiler-rt/lib/esan/working_set_posix.cpp new file mode 100644 index 000000000000..fcfa87128857 --- /dev/null +++ b/contrib/compiler-rt/lib/esan/working_set_posix.cpp @@ -0,0 +1,133 @@ +//===-- working_set_posix.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// POSIX-specific working set tool code. +//===----------------------------------------------------------------------===// + +#include "working_set.h" +#include "esan_flags.h" +#include "esan_shadow.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_linux.h" +#include +#include + +namespace __esan { + +// We only support regular POSIX threads with a single signal handler +// for the whole process == thread group. +// Thus we only need to store one app signal handler. +// FIXME: Store and use any alternate stack and signal flags set by +// the app. For now we just call the app handler from our handler. +static __sanitizer_sigaction AppSigAct; + +bool processWorkingSetSignal(int SigNum, void (*Handler)(int), + void (**Result)(int)) { + VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum); + if (SigNum == SIGSEGV) { + *Result = AppSigAct.handler; + AppSigAct.sigaction = (void (*)(int, void*, void*))Handler; + return false; // Skip real call. + } + return true; +} + +bool processWorkingSetSigaction(int SigNum, const void *ActVoid, + void *OldActVoid) { + VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum); + if (SigNum == SIGSEGV) { + const struct sigaction *Act = (const struct sigaction *) ActVoid; + struct sigaction *OldAct = (struct sigaction *) OldActVoid; + if (OldAct) + internal_memcpy(OldAct, &AppSigAct, sizeof(OldAct)); + if (Act) + internal_memcpy(&AppSigAct, Act, sizeof(AppSigAct)); + return false; // Skip real call. + } + return true; +} + +bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet) { + VPrintf(2, "%s\n", __FUNCTION__); + // All we need to do is ensure that SIGSEGV is not blocked. + // FIXME: we are not fully transparent as we do not pretend that + // SIGSEGV is still blocked on app queries: that would require + // per-thread mask tracking. + if (Set && (How == SIG_BLOCK || How == SIG_SETMASK)) { + if (internal_sigismember((__sanitizer_sigset_t *)Set, SIGSEGV)) { + VPrintf(1, "%s: removing SIGSEGV from the blocked set\n", __FUNCTION__); + internal_sigdelset((__sanitizer_sigset_t *)Set, SIGSEGV); + } + } + return true; +} + +static void reinstateDefaultHandler(int SigNum) { + __sanitizer_sigaction SigAct; + internal_memset(&SigAct, 0, sizeof(SigAct)); + SigAct.sigaction = (void (*)(int, void*, void*)) SIG_DFL; + int Res = internal_sigaction(SigNum, &SigAct, nullptr); + CHECK(Res == 0); + VPrintf(1, "Unregistered for %d handler\n", SigNum); +} + +// If this is a shadow fault, we handle it here; otherwise, we pass it to the +// app to handle it just as the app would do without our tool in place. +static void handleMemoryFault(int SigNum, void *Info, void *Ctx) { + if (SigNum == SIGSEGV) { + // We rely on si_addr being filled in (thus we do not support old kernels). + siginfo_t *SigInfo = (siginfo_t *)Info; + uptr Addr = (uptr)SigInfo->si_addr; + if (isShadowMem(Addr)) { + VPrintf(3, "Shadow fault @%p\n", Addr); + uptr PageSize = GetPageSizeCached(); + int Res = internal_mprotect((void *)RoundDownTo(Addr, PageSize), + PageSize, PROT_READ|PROT_WRITE); + CHECK(Res == 0); + } else if (AppSigAct.sigaction) { + // FIXME: For simplicity we ignore app options including its signal stack + // (we just use ours) and all the delivery flags. + AppSigAct.sigaction(SigNum, Info, Ctx); + } else { + // Crash instead of spinning with infinite faults. + reinstateDefaultHandler(SigNum); + } + } else + UNREACHABLE("signal not registered"); +} + +void registerMemoryFaultHandler() { + // We do not use an alternate signal stack, as doing so would require + // setting it up for each app thread. + // FIXME: This could result in problems with emulating the app's signal + // handling if the app relies on an alternate stack for SIGSEGV. + + // We require that SIGSEGV is not blocked. We use a sigprocmask + // interceptor to ensure that in the future. Here we ensure it for + // the current thread. We assume there are no other threads at this + // point during initialization, or that at least they do not block + // SIGSEGV. + __sanitizer_sigset_t SigSet; + internal_sigemptyset(&SigSet); + internal_sigprocmask(SIG_BLOCK, &SigSet, nullptr); + + __sanitizer_sigaction SigAct; + internal_memset(&SigAct, 0, sizeof(SigAct)); + SigAct.sigaction = handleMemoryFault; + // We want to handle nested signals b/c we need to handle a + // shadow fault in an app signal handler. + SigAct.sa_flags = SA_SIGINFO | SA_NODEFER; + int Res = internal_sigaction(SIGSEGV, &SigAct, &AppSigAct); + CHECK(Res == 0); + VPrintf(1, "Registered for SIGSEGV handler\n"); +} + +} // namespace __esan diff --git a/contrib/compiler-rt/lib/interception/interception_win.cc b/contrib/compiler-rt/lib/interception/interception_win.cc index 4c04c83b982b..8977d59ac4f1 100644 --- a/contrib/compiler-rt/lib/interception/interception_win.cc +++ b/contrib/compiler-rt/lib/interception/interception_win.cc @@ -10,16 +10,160 @@ // This file is a part of AddressSanitizer, an address sanity checker. // // Windows-specific interception methods. +// +// This file is implementing several hooking techniques to intercept calls +// to functions. The hooks are dynamically installed by modifying the assembly +// code. +// +// The hooking techniques are making assumptions on the way the code is +// generated and are safe under these assumptions. +// +// On 64-bit architecture, there is no direct 64-bit jump instruction. To allow +// arbitrary branching on the whole memory space, the notion of trampoline +// region is used. A trampoline region is a memory space withing 2G boundary +// where it is safe to add custom assembly code to build 64-bit jumps. +// +// Hooking techniques +// ================== +// +// 1) Detour +// +// The Detour hooking technique is assuming the presence of an header with +// padding and an overridable 2-bytes nop instruction (mov edi, edi). The +// nop instruction can safely be replaced by a 2-bytes jump without any need +// to save the instruction. A jump to the target is encoded in the function +// header and the nop instruction is replaced by a short jump to the header. +// +// head: 5 x nop head: jmp +// func: mov edi, edi --> func: jmp short +// [...] real: [...] +// +// This technique is only implemented on 32-bit architecture. +// Most of the time, Windows API are hookable with the detour technique. +// +// 2) Redirect Jump +// +// The redirect jump is applicable when the first instruction is a direct +// jump. The instruction is replaced by jump to the hook. +// +// func: jmp