From f1648d7693723304acaa08dca526c65868254735 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 3 Jul 2026 01:46:11 +0000 Subject: [PATCH 1/5] Update compiler-rt/include/profile from LLVM 21.1.8 to 22.1.8 While we are considering syncing compiler-rt to ToT, we are overdue for LLVM 22 library updates anyway, and reducing the gap between the current compiler and the new version will be helpful. --- .../include/profile/InstrProfData.inc | 2 +- .../include/profile/MemProfData.inc | 40 +- .../include/sanitizer/asan_interface.h | 8 + .../include/sanitizer/common_interface_defs.h | 52 ++ .../compiler-rt/lib/asan/asan_allocator.cpp | 113 +++- .../lib/compiler-rt/lib/asan/asan_allocator.h | 31 +- .../lib/asan/asan_descriptions.cpp | 10 + .../lib/compiler-rt/lib/asan/asan_errors.cpp | 14 +- system/lib/compiler-rt/lib/asan/asan_errors.h | 2 +- .../compiler-rt/lib/asan/asan_fake_stack.cpp | 198 ++++--- .../compiler-rt/lib/asan/asan_fake_stack.h | 39 +- .../lib/compiler-rt/lib/asan/asan_fuchsia.cpp | 8 +- .../lib/asan/asan_interceptors.cpp | 523 ++++++++++-------- .../compiler-rt/lib/asan/asan_interceptors.h | 227 ++++---- .../asan/asan_interceptors_memintrinsics.cpp | 4 +- .../asan/asan_interceptors_memintrinsics.h | 1 + .../compiler-rt/lib/asan/asan_interface.inc | 2 + system/lib/compiler-rt/lib/asan/asan_mac.cpp | 54 +- .../lib/asan/asan_malloc_linux.cpp | 10 +- .../compiler-rt/lib/asan/asan_malloc_mac.cpp | 6 +- .../compiler-rt/lib/asan/asan_malloc_win.cpp | 26 +- .../lib/compiler-rt/lib/asan/asan_mapping.h | 35 +- .../compiler-rt/lib/asan/asan_new_delete.cpp | 64 +-- .../lib/compiler-rt/lib/asan/asan_posix.cpp | 2 +- .../lib/compiler-rt/lib/asan/asan_thread.cpp | 32 +- system/lib/compiler-rt/lib/asan/asan_thread.h | 11 +- .../asan/asan_win_static_runtime_thunk.cpp | 4 + .../lib/compiler-rt/lib/builtins/assembly.h | 31 +- .../lib/compiler-rt/lib/builtins/crtbegin.c | 2 +- .../lib/builtins/gcc_personality_v0.c | 85 ++- .../lib/builtins/int_to_fp_impl.inc | 10 +- .../lib/interception/interception_aix.cpp | 51 +- .../lib/interception/interception_win.cpp | 4 + .../lib/compiler-rt/lib/lsan/lsan_allocator.h | 4 + .../lib/compiler-rt/lib/lsan/lsan_common.cpp | 22 +- system/lib/compiler-rt/lib/lsan/lsan_common.h | 8 +- .../lib/lsan/lsan_interceptors.cpp | 4 +- .../lib/compiler-rt/lib/lsan/lsan_posix.cpp | 4 +- system/lib/compiler-rt/lib/lsan/lsan_posix.h | 2 +- .../lib/compiler-rt/lib/lsan/lsan_thread.cpp | 8 +- system/lib/compiler-rt/lib/lsan/lsan_thread.h | 2 +- .../compiler-rt/lib/profile/GCDAProfiling.c | 5 + .../compiler-rt/lib/profile/InstrProfiling.c | 2 - .../compiler-rt/lib/profile/InstrProfiling.h | 5 + .../lib/profile/InstrProfilingFile.c | 5 + .../lib/profile/InstrProfilingMerge.c | 1 - .../lib/profile/InstrProfilingMergeFile.c | 1 - .../lib/profile/InstrProfilingPlatformLinux.c | 23 +- .../lib/profile/InstrProfilingPlatformOther.c | 10 +- .../lib/profile/InstrProfilingPort.h | 19 +- .../lib/profile/InstrProfilingUtil.c | 5 + .../sanitizer_allocator_primary32.h | 1 + .../sanitizer_allocator_primary64.h | 18 + .../lib/sanitizer_common/sanitizer_common.h | 17 +- .../sanitizer_common_interceptors.inc | 34 +- .../sanitizer_common_syscalls.inc | 18 + .../lib/sanitizer_common/sanitizer_file.cpp | 52 +- .../lib/sanitizer_common/sanitizer_file.h | 3 + .../lib/sanitizer_common/sanitizer_flags.inc | 7 + .../sanitizer_common/sanitizer_fuchsia.cpp | 33 +- .../lib/sanitizer_common/sanitizer_haiku.cpp | 4 +- .../sanitizer_internal_defs.h | 2 +- .../lib/sanitizer_common/sanitizer_libc.cpp | 8 + .../lib/sanitizer_common/sanitizer_libc.h | 1 + .../lib/sanitizer_common/sanitizer_linux.cpp | 12 +- .../lib/sanitizer_common/sanitizer_linux.h | 6 +- .../lib/sanitizer_common/sanitizer_mac.cpp | 359 ++++++++---- .../lib/sanitizer_common/sanitizer_mac.h | 5 + .../lib/sanitizer_common/sanitizer_netbsd.cpp | 4 +- .../lib/sanitizer_common/sanitizer_platform.h | 13 +- .../sanitizer_platform_interceptors.h | 9 +- .../sanitizer_platform_limits_posix.cpp | 21 +- .../sanitizer_platform_limits_posix.h | 4 +- .../lib/sanitizer_common/sanitizer_posix.cpp | 13 +- .../lib/sanitizer_common/sanitizer_posix.h | 3 +- .../sanitizer_posix_libcdep.cpp | 19 + .../sanitizer_procmaps_mac.cpp | 139 +++-- .../sanitizer_redefine_builtins.h | 3 +- .../sanitizer_signal_interceptors.inc | 42 +- .../sanitizer_common/sanitizer_stoptheworld.h | 2 +- .../sanitizer_stoptheworld_linux_libcdep.cpp | 95 +++- .../sanitizer_stoptheworld_mac.cpp | 6 +- .../sanitizer_stoptheworld_netbsd_libcdep.cpp | 14 +- .../sanitizer_stoptheworld_win.cpp | 4 +- .../sanitizer_symbolizer_internal.h | 6 +- .../sanitizer_symbolizer_libcdep.cpp | 12 +- .../sanitizer_symbolizer_mac.cpp | 115 +++- .../sanitizer_symbolizer_posix_libcdep.cpp | 43 +- .../sanitizer_thread_registry.cpp | 9 +- .../sanitizer_thread_registry.h | 8 +- .../lib/sanitizer_common/sanitizer_win.cpp | 4 +- .../ubsan_minimal/ubsan_minimal_handlers.cpp | 41 +- 92 files changed, 2162 insertions(+), 878 deletions(-) diff --git a/system/lib/compiler-rt/include/profile/InstrProfData.inc b/system/lib/compiler-rt/include/profile/InstrProfData.inc index 0496f240dc823..46d6bb5bd8896 100644 --- a/system/lib/compiler-rt/include/profile/InstrProfData.inc +++ b/system/lib/compiler-rt/include/profile/InstrProfData.inc @@ -722,7 +722,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, /* Raw profile format version (start from 1). */ #define INSTR_PROF_RAW_VERSION 10 /* Indexed profile format version (start from 1). */ -#define INSTR_PROF_INDEX_VERSION 12 +#define INSTR_PROF_INDEX_VERSION 13 /* Coverage mapping format version (start from 0). */ #define INSTR_PROF_COVMAP_VERSION 6 diff --git a/system/lib/compiler-rt/include/profile/MemProfData.inc b/system/lib/compiler-rt/include/profile/MemProfData.inc index 3f785bd23fce3..26badddae6f3a 100644 --- a/system/lib/compiler-rt/include/profile/MemProfData.inc +++ b/system/lib/compiler-rt/include/profile/MemProfData.inc @@ -33,11 +33,10 @@ (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129) // The version number of the raw binary format. -#define MEMPROF_RAW_VERSION 4ULL +#define MEMPROF_RAW_VERSION 5ULL // Currently supported versions. -#define MEMPROF_RAW_SUPPORTED_VERSIONS \ - { 3ULL, 4ULL } +#define MEMPROF_RAW_SUPPORTED_VERSIONS {3ULL, 4ULL, 5ULL} #define MEMPROF_V3_MIB_SIZE 132ULL; @@ -229,6 +228,41 @@ void Merge(const MemInfoBlock &newMIB) { } __attribute__((__packed__)); #endif +constexpr int MantissaBits = 12; +constexpr int ExponentBits = 4; +constexpr uint16_t MaxMantissa = (1U << MantissaBits) - 1; +constexpr uint16_t MaxExponent = (1U << ExponentBits) - 1; +constexpr uint64_t MaxRepresentableValue = static_cast(MaxMantissa) + << MaxExponent; + +// Encodes a 64-bit unsigned integer into a 16-bit scaled integer format. +inline uint16_t encodeHistogramCount(uint64_t Count) { + if (Count == 0) + return 0; + + if (Count > MaxRepresentableValue) + Count = MaxRepresentableValue; + + if (Count <= MaxMantissa) + return Count; + + uint64_t M = Count; + uint16_t E = 0; + while (M > MaxMantissa) { + M = (M + 1) >> 1; + E++; + } + return (E << MantissaBits) | static_cast(M); +} + +// Decodes a 16-bit scaled integer and returns the +// decoded 64-bit unsigned integer. +inline uint64_t decodeHistogramCount(uint16_t EncodedValue) { + const uint16_t E = EncodedValue >> MantissaBits; + const uint16_t M = EncodedValue & MaxMantissa; + return static_cast(M) << E; +} + } // namespace memprof } // namespace llvm diff --git a/system/lib/compiler-rt/include/sanitizer/asan_interface.h b/system/lib/compiler-rt/include/sanitizer/asan_interface.h index 37b6d08f4db19..544f2e4b32687 100644 --- a/system/lib/compiler-rt/include/sanitizer/asan_interface.h +++ b/system/lib/compiler-rt/include/sanitizer/asan_interface.h @@ -333,6 +333,14 @@ void SANITIZER_CDECL __asan_handle_no_return(void); /// trace. Returns 1 if successful, 0 if not. int SANITIZER_CDECL __asan_update_allocation_context(void *addr); +/// Suppresses fake stack for the current thread. +/// Temporarily disables use-after-return detection for current thread. +void SANITIZER_CDECL __asan_suppress_fake_stack(void); + +/// Unsupresses fake stack for the current thread. +/// Should be paired with a previous __asan_suppress_fake_stack() call. +void SANITIZER_CDECL __asan_unsuppress_fake_stack(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h b/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h index 57313f9bc80e6..51104093758cd 100644 --- a/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h +++ b/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h @@ -156,8 +156,15 @@ int SANITIZER_CDECL __sanitizer_acquire_crash_state(); /// \param end End of memory region. /// \param old_mid Old middle of memory region. /// \param new_mid New middle of memory region. +#ifdef __SANITIZER_DISABLE_CONTAINER_OVERFLOW__ +__attribute__((__internal_linkage__)) inline void SANITIZER_CDECL +__sanitizer_annotate_contiguous_container(const void *beg, const void *end, + const void *old_mid, + const void *new_mid) {} +#else void SANITIZER_CDECL __sanitizer_annotate_contiguous_container( const void *beg, const void *end, const void *old_mid, const void *new_mid); +#endif /// Similar to __sanitizer_annotate_contiguous_container. /// @@ -188,10 +195,18 @@ void SANITIZER_CDECL __sanitizer_annotate_contiguous_container( /// \param old_container_end End of used region. /// \param new_container_beg New beginning of used region. /// \param new_container_end New end of used region. +#ifdef __SANITIZER_DISABLE_CONTAINER_OVERFLOW__ +__attribute__((__internal_linkage__)) inline void + SANITIZER_CDECL __sanitizer_annotate_double_ended_contiguous_container( + const void *storage_beg, const void *storage_end, + const void *old_container_beg, const void *old_container_end, + const void *new_container_beg, const void *new_container_end) {} +#else void SANITIZER_CDECL __sanitizer_annotate_double_ended_contiguous_container( const void *storage_beg, const void *storage_end, const void *old_container_beg, const void *old_container_end, const void *new_container_beg, const void *new_container_end); +#endif /// Copies memory annotations from a source storage region to a destination /// storage region. After the operation, the destination region has the same @@ -226,9 +241,17 @@ void SANITIZER_CDECL __sanitizer_annotate_double_ended_contiguous_container( /// \param src_end End of the source container region. /// \param dst_begin Begin of the destination container region. /// \param dst_end End of the destination container region. +#ifdef __SANITIZER_DISABLE_CONTAINER_OVERFLOW__ +__attribute__((__internal_linkage__)) inline void SANITIZER_CDECL +__sanitizer_copy_contiguous_container_annotations(const void *src_begin, + const void *src_end, + const void *dst_begin, + const void *dst_end) {} +#else void SANITIZER_CDECL __sanitizer_copy_contiguous_container_annotations( const void *src_begin, const void *src_end, const void *dst_begin, const void *dst_end); +#endif /// Returns true if the contiguous container [beg, end) is properly /// poisoned. @@ -246,9 +269,16 @@ void SANITIZER_CDECL __sanitizer_copy_contiguous_container_annotations( /// /// \returns True if the contiguous container [beg, end) is properly /// poisoned. +#ifdef __SANITIZER_DISABLE_CONTAINER_OVERFLOW__ +__attribute__((__internal_linkage__)) inline int + SANITIZER_CDECL __sanitizer_verify_contiguous_container(const void *beg, + const void *mid, + const void *end) {} +#else int SANITIZER_CDECL __sanitizer_verify_contiguous_container(const void *beg, const void *mid, const void *end); +#endif /// Returns true if the double ended contiguous /// container [storage_beg, storage_end) is properly poisoned. @@ -271,9 +301,17 @@ int SANITIZER_CDECL __sanitizer_verify_contiguous_container(const void *beg, /// \returns True if the double-ended contiguous container [storage_beg, /// container_beg, container_end, end) is properly poisoned - only /// [container_beg; container_end) is addressable. +#ifdef __SANITIZER_DISABLE_CONTAINER_OVERFLOW__ +__attribute__((__internal_linkage__)) inline int SANITIZER_CDECL +__sanitizer_verify_double_ended_contiguous_container(const void *storage_beg, + const void *container_beg, + const void *container_end, + const void *storage_end) {} +#else int SANITIZER_CDECL __sanitizer_verify_double_ended_contiguous_container( const void *storage_beg, const void *container_beg, const void *container_end, const void *storage_end); +#endif /// Similar to __sanitizer_verify_contiguous_container() but also /// returns the address of the first improperly poisoned byte. @@ -285,8 +323,15 @@ int SANITIZER_CDECL __sanitizer_verify_double_ended_contiguous_container( /// \param end Old end of memory region. /// /// \returns The bad address or NULL. +#ifdef __SANITIZER_DISABLE_CONTAINER_OVERFLOW__ +__attribute__((__internal_linkage__)) inline const void *SANITIZER_CDECL +__sanitizer_contiguous_container_find_bad_address(const void *beg, + const void *mid, + const void *end) {} +#else const void *SANITIZER_CDECL __sanitizer_contiguous_container_find_bad_address( const void *beg, const void *mid, const void *end); +#endif /// returns the address of the first improperly poisoned byte. /// @@ -298,10 +343,17 @@ const void *SANITIZER_CDECL __sanitizer_contiguous_container_find_bad_address( /// \param storage_end End of memory region. /// /// \returns The bad address or NULL. +#ifdef __SANITIZER_DISABLE_CONTAINER_OVERFLOW__ +__attribute__((__internal_linkage__)) inline const void *SANITIZER_CDECL +__sanitizer_double_ended_contiguous_container_find_bad_address( + const void *storage_beg, const void *container_beg, + const void *container_end, const void *storage_end) {} +#else const void *SANITIZER_CDECL __sanitizer_double_ended_contiguous_container_find_bad_address( const void *storage_beg, const void *container_beg, const void *container_end, const void *storage_end); +#endif /// Prints the stack trace leading to this call (useful for calling from the /// debugger). diff --git a/system/lib/compiler-rt/lib/asan/asan_allocator.cpp b/system/lib/compiler-rt/lib/asan/asan_allocator.cpp index d3c0288285b86..752ba9ab32c71 100644 --- a/system/lib/compiler-rt/lib/asan/asan_allocator.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_allocator.cpp @@ -547,6 +547,7 @@ struct Allocator { ComputeUserRequestedAlignmentLog(alignment); if (alignment < min_alignment) alignment = min_alignment; + bool upgraded_from_zero = false; if (size == 0) { // We'd be happy to avoid allocating memory for zero-size requests, but // some programs/tests depend on this behavior and assume that malloc @@ -555,6 +556,7 @@ struct Allocator { // consecutive "new" calls must be different even if the allocated size // is zero. size = 1; + upgraded_from_zero = true; } CHECK(IsPowerOfTwo(alignment)); uptr rz_log = ComputeRZLog(size); @@ -637,6 +639,10 @@ struct Allocator { *shadow = fl.poison_partial ? (size & (ASAN_SHADOW_GRANULARITY - 1)) : 0; } + if (upgraded_from_zero) + PoisonShadow(user_beg, ASAN_SHADOW_GRANULARITY, + kAsanHeapLeftRedzoneMagic); + AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.mallocs++; thread_stats.malloced += size; @@ -1007,13 +1013,8 @@ void PrintInternalAllocatorStats() { instance.PrintStats(); } -void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) { - instance.Deallocate(ptr, 0, 0, stack, alloc_type); -} - -void asan_delete(void *ptr, uptr size, uptr alignment, - BufferedStackTrace *stack, AllocType alloc_type) { - instance.Deallocate(ptr, size, alignment, stack, alloc_type); +void asan_free(void *ptr, BufferedStackTrace *stack) { + instance.Deallocate(ptr, 0, 0, stack, FROM_MALLOC); } void *asan_malloc(uptr size, BufferedStackTrace *stack) { @@ -1068,8 +1069,7 @@ void *asan_pvalloc(uptr size, BufferedStackTrace *stack) { instance.Allocate(size, PageSize, stack, FROM_MALLOC, true)); } -void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, - AllocType alloc_type) { +void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack) { if (UNLIKELY(!IsPowerOfTwo(alignment))) { errno = errno_EINVAL; if (AllocatorMayReturnNull()) @@ -1077,7 +1077,7 @@ void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, ReportInvalidAllocationAlignment(alignment, stack); } return SetErrnoOnNull( - instance.Allocate(size, alignment, stack, alloc_type, true)); + instance.Allocate(size, alignment, stack, FROM_MALLOC, true)); } void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) { @@ -1117,6 +1117,99 @@ uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp) { return usable_size; } +namespace { + +void *asan_new(uptr size, BufferedStackTrace *stack, bool array) { + return SetErrnoOnNull( + instance.Allocate(size, 0, stack, array ? FROM_NEW_BR : FROM_NEW, true)); +} + +void *asan_new_aligned(uptr size, uptr alignment, BufferedStackTrace *stack, + bool array) { + if (UNLIKELY(alignment == 0 || !IsPowerOfTwo(alignment))) { + errno = errno_EINVAL; + if (AllocatorMayReturnNull()) + return nullptr; + ReportInvalidAllocationAlignment(alignment, stack); + } + return SetErrnoOnNull(instance.Allocate( + size, alignment, stack, array ? FROM_NEW_BR : FROM_NEW, true)); +} + +void asan_delete(void *ptr, BufferedStackTrace *stack, bool array) { + instance.Deallocate(ptr, 0, 0, stack, array ? FROM_NEW_BR : FROM_NEW); +} + +void asan_delete_aligned(void *ptr, uptr alignment, BufferedStackTrace *stack, + bool array) { + instance.Deallocate(ptr, 0, alignment, stack, array ? FROM_NEW_BR : FROM_NEW); +} + +void asan_delete_sized(void *ptr, uptr size, BufferedStackTrace *stack, + bool array) { + instance.Deallocate(ptr, size, 0, stack, array ? FROM_NEW_BR : FROM_NEW); +} + +void asan_delete_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack, bool array) { + instance.Deallocate(ptr, size, alignment, stack, + array ? FROM_NEW_BR : FROM_NEW); +} + +} // namespace + +void *asan_new(uptr size, BufferedStackTrace *stack) { + return asan_new(size, stack, /*array=*/false); +} + +void *asan_new_aligned(uptr size, uptr alignment, BufferedStackTrace *stack) { + return asan_new_aligned(size, alignment, stack, /*array=*/false); +} + +void *asan_new_array(uptr size, BufferedStackTrace *stack) { + return asan_new(size, stack, /*array=*/true); +} + +void *asan_new_array_aligned(uptr size, uptr alignment, + BufferedStackTrace *stack) { + return asan_new_aligned(size, alignment, stack, /*array=*/true); +} + +void asan_delete(void *ptr, BufferedStackTrace *stack) { + asan_delete(ptr, stack, /*array=*/false); +} + +void asan_delete_aligned(void *ptr, uptr alignment, BufferedStackTrace *stack) { + asan_delete_aligned(ptr, alignment, stack, /*array=*/false); +} + +void asan_delete_sized(void *ptr, uptr size, BufferedStackTrace *stack) { + asan_delete_sized(ptr, size, stack, /*array=*/false); +} + +void asan_delete_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack) { + asan_delete_sized_aligned(ptr, size, alignment, stack, /*array=*/false); +} + +void asan_delete_array(void *ptr, BufferedStackTrace *stack) { + asan_delete(ptr, stack, /*array=*/true); +} + +void asan_delete_array_aligned(void *ptr, uptr alignment, + BufferedStackTrace *stack) { + asan_delete_aligned(ptr, alignment, stack, /*array=*/true); +} + +void asan_delete_array_sized(void *ptr, uptr size, BufferedStackTrace *stack) { + asan_delete_sized(ptr, size, stack, /*array=*/true); +} + +void asan_delete_array_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack) { + asan_delete_sized_aligned(ptr, size, alignment, stack, /*array=*/true); +} + uptr asan_mz_size(const void *ptr) { return instance.AllocationSize(reinterpret_cast(ptr)); } diff --git a/system/lib/compiler-rt/lib/asan/asan_allocator.h b/system/lib/compiler-rt/lib/asan/asan_allocator.h index 247d8bb77c984..4131fda096930 100644 --- a/system/lib/compiler-rt/lib/asan/asan_allocator.h +++ b/system/lib/compiler-rt/lib/asan/asan_allocator.h @@ -198,9 +198,14 @@ const uptr kAllocatorSpace = ~(uptr)0; # endif // SANITIZER_APPLE # if defined(__powerpc64__) +# if SANITIZER_AIX +const uptr kAllocatorSize = 1ULL << 38; // 256G. +# else const uptr kAllocatorSize = 0x20000000000ULL; // 2T. +# endif typedef DefaultSizeClassMap SizeClassMap; -# elif defined(__aarch64__) && SANITIZER_ANDROID +# elif defined(__aarch64__) && \ + (SANITIZER_ANDROID || defined(SANITIZER_AARCH64_39BIT_VA)) // Android needs to support 39, 42 and 48 bit VMA. const uptr kAllocatorSize = 0x2000000000ULL; // 128G. typedef VeryCompactSizeClassMap SizeClassMap; @@ -270,11 +275,8 @@ struct AsanThreadLocalMallocStorage { AsanThreadLocalMallocStorage() {} }; -void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, - AllocType alloc_type); -void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type); -void asan_delete(void *ptr, uptr size, uptr alignment, - BufferedStackTrace *stack, AllocType alloc_type); +void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack); +void asan_free(void *ptr, BufferedStackTrace *stack); void *asan_malloc(uptr size, BufferedStackTrace *stack); void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack); @@ -289,6 +291,23 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size, BufferedStackTrace *stack); uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp); +void *asan_new(uptr size, BufferedStackTrace *stack); +void *asan_new_aligned(uptr size, uptr alignment, BufferedStackTrace *stack); +void *asan_new_array(uptr size, BufferedStackTrace *stack); +void *asan_new_array_aligned(uptr size, uptr alignment, + BufferedStackTrace *stack); +void asan_delete(void *ptr, BufferedStackTrace *stack); +void asan_delete_aligned(void *ptr, uptr alignment, BufferedStackTrace *stack); +void asan_delete_sized(void *ptr, uptr size, BufferedStackTrace *stack); +void asan_delete_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack); +void asan_delete_array(void *ptr, BufferedStackTrace *stack); +void asan_delete_array_aligned(void *ptr, uptr alignment, + BufferedStackTrace *stack); +void asan_delete_array_sized(void *ptr, uptr size, BufferedStackTrace *stack); +void asan_delete_array_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack); + uptr asan_mz_size(const void *ptr); void asan_mz_force_lock(); void asan_mz_force_unlock(); diff --git a/system/lib/compiler-rt/lib/asan/asan_descriptions.cpp b/system/lib/compiler-rt/lib/asan/asan_descriptions.cpp index 0c30959b23e28..18c2a6c571c1f 100644 --- a/system/lib/compiler-rt/lib/asan/asan_descriptions.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_descriptions.cpp @@ -449,10 +449,12 @@ AddressDescription::AddressDescription(uptr addr, uptr access_size, // are put to the STACK region for unknown reasons. Check global first can // workaround this issue. // TODO: Look into whether there's a different solution to this problem. +#if SANITIZER_AIX if (GetGlobalAddressInformation(addr, access_size, &data.global)) { data.kind = kAddressKindGlobal; return; } +#endif if (GetHeapAddressInformation(addr, access_size, &data.heap)) { data.kind = kAddressKindHeap; @@ -471,6 +473,14 @@ AddressDescription::AddressDescription(uptr addr, uptr access_size, return; } +// GetGlobalAddressInformation is called earlier on AIX due to a workaround +#if !SANITIZER_AIX + if (GetGlobalAddressInformation(addr, access_size, &data.global)) { + data.kind = kAddressKindGlobal; + return; + } +#endif + data.kind = kAddressKindWild; data.wild.addr = addr; data.wild.access_size = access_size; diff --git a/system/lib/compiler-rt/lib/asan/asan_errors.cpp b/system/lib/compiler-rt/lib/asan/asan_errors.cpp index a1d5f7f144faf..42793787eeb53 100644 --- a/system/lib/compiler-rt/lib/asan/asan_errors.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_errors.cpp @@ -525,11 +525,15 @@ ErrorGeneric::ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr, } 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"); + Printf( + "HINT: if you don't care about these errors you may set " + "ASAN_OPTIONS=detect_container_overflow=0.\n" + "Or if supported by the container library, pass " + "-D__SANITIZER_DISABLE_CONTAINER_OVERFLOW__ to the compiler to disable " + " instrumentation.\n" + "If you suspect a false positive see also: " + "https://github.com/google/sanitizers/wiki/" + "AddressSanitizerContainerOverflow.\n"); } static void PrintShadowByte(InternalScopedString *str, const char *before, diff --git a/system/lib/compiler-rt/lib/asan/asan_errors.h b/system/lib/compiler-rt/lib/asan/asan_errors.h index b3af655e66639..f339b35d2a764 100644 --- a/system/lib/compiler-rt/lib/asan/asan_errors.h +++ b/system/lib/compiler-rt/lib/asan/asan_errors.h @@ -362,7 +362,7 @@ struct ErrorBadParamsToCopyContiguousContainerAnnotations : ErrorBase { u32 tid, BufferedStackTrace *stack_, uptr old_storage_beg_, uptr old_storage_end_, uptr new_storage_beg_, uptr new_storage_end_) : ErrorBase(tid, 10, - "bad-__sanitizer_annotate_double_ended_contiguous_container"), + "bad-__sanitizer_copy_contiguous_container_annotations"), stack(stack_), old_storage_beg(old_storage_beg_), old_storage_end(old_storage_end_), diff --git a/system/lib/compiler-rt/lib/asan/asan_fake_stack.cpp b/system/lib/compiler-rt/lib/asan/asan_fake_stack.cpp index 0f696075fb78d..af73d31b8a5dc 100644 --- a/system/lib/compiler-rt/lib/asan/asan_fake_stack.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_fake_stack.cpp @@ -28,7 +28,7 @@ static const u64 kAllocaRedzoneMask = 31UL; // For small size classes inline PoisonShadow for better performance. ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) { CHECK(AddrIsAlignedByGranularity(ptr + size)); - u64 *shadow = reinterpret_cast(MemToShadow(ptr)); + u64* shadow = reinterpret_cast(MemToShadow(ptr)); if (ASAN_SHADOW_SCALE == 3 && class_id <= 6) { // This code expects ASAN_SHADOW_SCALE=3. for (uptr i = 0; i < (((uptr)1) << class_id); i++) { @@ -47,25 +47,41 @@ ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) { } } -FakeStack *FakeStack::Create(uptr stack_size_log) { +FakeStack* FakeStack::Create(uptr stack_size_log) { static uptr kMinStackSizeLog = 16; static uptr kMaxStackSizeLog = FIRST_32_SECOND_64(24, 28); if (stack_size_log < kMinStackSizeLog) stack_size_log = kMinStackSizeLog; if (stack_size_log > kMaxStackSizeLog) stack_size_log = kMaxStackSizeLog; + CHECK_LE(kMaxStackFrameSizeLog, stack_size_log); uptr size = RequiredSize(stack_size_log); - FakeStack *res = reinterpret_cast( - flags()->uar_noreserve ? MmapNoReserveOrDie(size, "FakeStack") - : MmapOrDie(size, "FakeStack")); + uptr padded_size = size + kMaxStackFrameSize; + void* true_res = reinterpret_cast( + flags()->uar_noreserve ? MmapNoReserveOrDie(padded_size, "FakeStack") + : MmapOrDie(padded_size, "FakeStack")); + // GetFrame() requires the property that + // (res + kFlagsOffset + SizeRequiredForFlags(stack_size_log)) is aligned to + // kMaxStackFrameSize. + // We didn't use MmapAlignedOrDieOnFatalError, because it requires that the + // *size* is a power of 2, which is an overly strong condition. + static_assert(alignof(FakeStack) <= kMaxStackFrameSize); + FakeStack* res = reinterpret_cast( + RoundUpTo( + (uptr)true_res + kFlagsOffset + SizeRequiredForFlags(stack_size_log), + kMaxStackFrameSize) - + kFlagsOffset - SizeRequiredForFlags(stack_size_log)); + res->true_start = true_res; res->stack_size_log_ = stack_size_log; - u8 *p = reinterpret_cast(res); + u8* p = reinterpret_cast(res); VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; " - "mmapped %zdK, noreserve=%d \n", - GetCurrentTidOrInvalid(), (void *)p, - (void *)(p + FakeStack::RequiredSize(stack_size_log)), stack_size_log, - size >> 10, flags()->uar_noreserve); + "mmapped %zdK, noreserve=%d, true_start: %p, start of first frame: " + "0x%zx\n", + GetCurrentTidOrInvalid(), (void*)p, + (void*)(p + FakeStack::RequiredSize(stack_size_log)), stack_size_log, + size >> 10, flags()->uar_noreserve, res->true_start, + res->GetFrame(stack_size_log, /*class_id*/ 0, /*pos*/ 0)); return res; } @@ -79,8 +95,10 @@ void FakeStack::Destroy(int tid) { Report("T%d: FakeStack destroyed: %s\n", tid, str.data()); } uptr size = RequiredSize(stack_size_log_); - FlushUnneededASanShadowMemory(reinterpret_cast(this), size); - UnmapOrDie(this, size); + uptr padded_size = size + kMaxStackFrameSize; + FlushUnneededASanShadowMemory(reinterpret_cast(true_start), + padded_size); + UnmapOrDie(true_start, padded_size); } void FakeStack::PoisonAll(u8 magic) { @@ -91,14 +109,14 @@ void FakeStack::PoisonAll(u8 magic) { #if !defined(_MSC_VER) || defined(__clang__) ALWAYS_INLINE USED #endif -FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id, - uptr real_stack) { + FakeFrame* FakeStack::Allocate(uptr stack_size_log, uptr class_id, + uptr real_stack) { CHECK_LT(class_id, kNumberOfSizeClasses); if (needs_gc_) GC(real_stack); - uptr &hint_position = hint_position_[class_id]; + uptr& hint_position = hint_position_[class_id]; const int num_iter = NumberOfFrames(stack_size_log, class_id); - u8 *flags = GetFlags(stack_size_log, class_id); + u8* flags = GetFlags(stack_size_log, class_id); for (int i = 0; i < num_iter; i++) { uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++); // This part is tricky. On one hand, checking and setting flags[pos] @@ -108,22 +126,24 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id, // and so will not touch this particular byte. So, it is safe to do this // with regular non-atomic load and store (at least I was not able to make // this code crash). - if (flags[pos]) continue; + if (flags[pos]) + continue; flags[pos] = 1; - FakeFrame *res = reinterpret_cast( - GetFrame(stack_size_log, class_id, pos)); + FakeFrame* res = + reinterpret_cast(GetFrame(stack_size_log, class_id, pos)); res->real_stack = real_stack; *SavedFlagPtr(reinterpret_cast(res), class_id) = &flags[pos]; return res; } - return nullptr; // We are out of fake stack. + return nullptr; // We are out of fake stack. } -uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) { +uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr* frame_beg, uptr* frame_end) { uptr stack_size_log = this->stack_size_log(); uptr beg = reinterpret_cast(GetFrame(stack_size_log, 0, 0)); uptr end = reinterpret_cast(this) + RequiredSize(stack_size_log); - if (ptr < beg || ptr >= end) return 0; + if (ptr < beg || ptr >= end) + return 0; uptr class_id = (ptr - beg) >> stack_size_log; uptr base = beg + (class_id << stack_size_log); CHECK_LE(base, ptr); @@ -135,9 +155,7 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) { return res; } -void FakeStack::HandleNoReturn() { - needs_gc_ = true; -} +void FakeStack::HandleNoReturn() { needs_gc_ = true; } // Hack: The statement below is not true if we take into account sigaltstack or // makecontext. It should be possible to make GC to discard wrong stack frame if @@ -152,7 +170,7 @@ void FakeStack::HandleNoReturn() { // We do it based on their 'real_stack' values -- everything that is lower // than the current real_stack is garbage. NOINLINE void FakeStack::GC(uptr real_stack) { - AsanThread *curr_thread = GetCurrentThread(); + AsanThread* curr_thread = GetCurrentThread(); if (!curr_thread) return; // Try again when we have a thread. auto top = curr_thread->stack_top(); @@ -161,12 +179,13 @@ NOINLINE void FakeStack::GC(uptr real_stack) { return; // Not the default stack. for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) { - u8 *flags = GetFlags(stack_size_log(), class_id); + u8* flags = GetFlags(stack_size_log(), class_id); for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n; i++) { - if (flags[i] == 0) continue; // not allocated. - FakeFrame *ff = reinterpret_cast( - GetFrame(stack_size_log(), class_id, i)); + if (flags[i] == 0) + continue; // not allocated. + FakeFrame* ff = + reinterpret_cast(GetFrame(stack_size_log(), class_id, i)); // GC only on the default stack. if (bottom < ff->real_stack && ff->real_stack < real_stack) { flags[i] = 0; @@ -179,14 +198,15 @@ NOINLINE void FakeStack::GC(uptr real_stack) { needs_gc_ = false; } -void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) { +void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void* arg) { for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) { - u8 *flags = GetFlags(stack_size_log(), class_id); + u8* flags = GetFlags(stack_size_log(), class_id); for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n; i++) { - if (flags[i] == 0) continue; // not allocated. - FakeFrame *ff = reinterpret_cast( - GetFrame(stack_size_log(), class_id, i)); + if (flags[i] == 0) + continue; // not allocated. + FakeFrame* ff = + reinterpret_cast(GetFrame(stack_size_log(), class_id, i)); uptr begin = reinterpret_cast(ff); callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg); } @@ -194,44 +214,65 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) { } #if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA -static THREADLOCAL FakeStack *fake_stack_tls; +static THREADLOCAL FakeStack* fake_stack_tls; -FakeStack *GetTLSFakeStack() { - return fake_stack_tls; -} -void SetTLSFakeStack(FakeStack *fs) { - fake_stack_tls = fs; -} +static FakeStack* GetTLSFakeStack() { return fake_stack_tls; } +static void SetTLSFakeStack(FakeStack* fs) { fake_stack_tls = fs; } +void ResetTLSFakeStack() { fake_stack_tls = nullptr; } #else -FakeStack *GetTLSFakeStack() { return 0; } -void SetTLSFakeStack(FakeStack *fs) { } +static FakeStack* GetTLSFakeStack() { return nullptr; } +static void SetTLSFakeStack(FakeStack*) {} +void ResetTLSFakeStack() {} #endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA -static FakeStack *GetFakeStack() { - AsanThread *t = GetCurrentThread(); - if (!t) return nullptr; +static void SuppressFakeStack() { + AsanThread* t = GetCurrentThread(); + if (t) { + t->SuppressFakeStack(); + } +} + +static void UnsuppressFakeStack() { + AsanThread* t = GetCurrentThread(); + if (t) { + t->UnsuppressFakeStack(); + } +} + +static FakeStack* GetFakeStack() { + AsanThread* t = GetCurrentThread(); + if (!t || t->IsFakeStackSuppressed()) + return nullptr; return t->get_or_create_fake_stack(); } -static FakeStack *GetFakeStackFast() { - if (FakeStack *fs = GetTLSFakeStack()) +static FakeStack* GetFakeStackFast() { + FakeStack* fs = GetTLSFakeStack(); + if (LIKELY(fs)) return fs; if (!__asan_option_detect_stack_use_after_return) return nullptr; - return GetFakeStack(); + fs = GetFakeStack(); + if (LIKELY(fs)) + SetTLSFakeStack(fs); + return fs; } -static FakeStack *GetFakeStackFastAlways() { - if (FakeStack *fs = GetTLSFakeStack()) +static FakeStack* GetFakeStackFastAlways() { + FakeStack* fs = GetTLSFakeStack(); + if (LIKELY(fs)) return fs; - return GetFakeStack(); + fs = GetFakeStack(); + if (LIKELY(fs)) + SetTLSFakeStack(fs); + return fs; } static ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) { - FakeStack *fs = GetFakeStackFast(); + FakeStack* fs = GetFakeStackFast(); if (!fs) return 0; - FakeFrame *ff = + FakeFrame* ff = fs->Allocate(fs->stack_size_log(), class_id, GET_CURRENT_FRAME()); if (!ff) return 0; // Out of fake stack. @@ -241,10 +282,10 @@ static ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) { } static ALWAYS_INLINE uptr OnMallocAlways(uptr class_id, uptr size) { - FakeStack *fs = GetFakeStackFastAlways(); + FakeStack* fs = GetFakeStackFastAlways(); if (!fs) return 0; - FakeFrame *ff = + FakeFrame* ff = fs->Allocate(fs->stack_size_log(), class_id, GET_CURRENT_FRAME()); if (!ff) return 0; // Out of fake stack. @@ -258,17 +299,17 @@ static ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) { SetShadow(ptr, size, class_id, kMagic8); } -} // namespace __asan +} // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; #define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \ - __asan_stack_malloc_##class_id(uptr size) { \ + __asan_stack_malloc_##class_id(uptr size) { \ return OnMalloc(class_id, size); \ } \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \ - __asan_stack_malloc_always_##class_id(uptr size) { \ + __asan_stack_malloc_always_##class_id(uptr size) { \ return OnMallocAlways(class_id, size); \ } \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \ @@ -293,21 +334,25 @@ extern "C" { // -asan-use-after-return=never, after modal UAR flag lands // (https://github.com/google/sanitizers/issues/1394) SANITIZER_INTERFACE_ATTRIBUTE -void *__asan_get_current_fake_stack() { return GetFakeStackFast(); } +void* __asan_get_current_fake_stack() { return GetFakeStackFast(); } SANITIZER_INTERFACE_ATTRIBUTE -void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, - void **end) { - FakeStack *fs = reinterpret_cast(fake_stack); - if (!fs) return nullptr; +void* __asan_addr_is_in_fake_stack(void* fake_stack, void* addr, void** beg, + void** end) { + FakeStack* fs = reinterpret_cast(fake_stack); + if (!fs) + return nullptr; uptr frame_beg, frame_end; - FakeFrame *frame = reinterpret_cast(fs->AddrIsInFakeStack( + FakeFrame* frame = reinterpret_cast(fs->AddrIsInFakeStack( reinterpret_cast(addr), &frame_beg, &frame_end)); - if (!frame) return nullptr; + if (!frame) + return nullptr; if (frame->magic != kCurrentStackFrameMagic) return nullptr; - if (beg) *beg = reinterpret_cast(frame_beg); - if (end) *end = reinterpret_cast(frame_end); + if (beg) + *beg = reinterpret_cast(frame_beg); + if (end) + *end = reinterpret_cast(frame_end); return reinterpret_cast(frame->real_stack); } @@ -326,9 +371,14 @@ void __asan_alloca_poison(uptr addr, uptr size) { SANITIZER_INTERFACE_ATTRIBUTE void __asan_allocas_unpoison(uptr top, uptr bottom) { - if ((!top) || (top > bottom)) return; - REAL(memset) - (reinterpret_cast(MemToShadow(top)), 0, - (bottom - top) / ASAN_SHADOW_GRANULARITY); + if ((!top) || (top > bottom)) + return; + REAL(memset)(reinterpret_cast(MemToShadow(top)), 0, + (bottom - top) / ASAN_SHADOW_GRANULARITY); } -} // extern "C" + +SANITIZER_INTERFACE_ATTRIBUTE +void __asan_suppress_fake_stack() { return SuppressFakeStack(); } +SANITIZER_INTERFACE_ATTRIBUTE +void __asan_unsuppress_fake_stack() { return UnsuppressFakeStack(); } +} // extern "C" diff --git a/system/lib/compiler-rt/lib/asan/asan_fake_stack.h b/system/lib/compiler-rt/lib/asan/asan_fake_stack.h index 270a19816d6e2..593c1373c8ff1 100644 --- a/system/lib/compiler-rt/lib/asan/asan_fake_stack.h +++ b/system/lib/compiler-rt/lib/asan/asan_fake_stack.h @@ -32,12 +32,12 @@ struct FakeFrame { // is not popped but remains there for quite some time until gets used again. // So, we poison the objects on the fake stack when function returns. // It helps us find use-after-return bugs. -// // The FakeStack objects is allocated by a single mmap call and has no other // pointers. The size of the fake stack depends on the actual thread stack size // and thus can not be a constant. // stack_size is a power of two greater or equal to the thread's stack size; // we store it as its logarithm (stack_size_log). +// FakeStack is padded such that GetFrame() is aligned to BytesInSizeClass(). // FakeStack has kNumberOfSizeClasses (11) size classes, each size class // is a power of two, starting from 64 bytes. Each size class occupies // stack_size bytes and thus can allocate @@ -56,6 +56,9 @@ struct FakeFrame { class FakeStack { static const uptr kMinStackFrameSizeLog = 6; // Min frame is 64B. static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K. + static_assert(kMaxStackFrameSizeLog >= kMinStackFrameSizeLog); + + static const u64 kMaxStackFrameSize = 1 << kMaxStackFrameSizeLog; public: static const uptr kNumberOfSizeClasses = @@ -66,7 +69,7 @@ class FakeStack { void Destroy(int tid); - // stack_size_log is at least 15 (stack_size >= 32K). + // min_uar_stack_size_log is 16 (stack_size >= 64KB) static uptr SizeRequiredForFlags(uptr stack_size_log) { return ((uptr)1) << (stack_size_log + 1 - kMinStackFrameSizeLog); } @@ -110,6 +113,28 @@ class FakeStack { } // Get frame by class_id and pos. + // Return values are guaranteed to be aligned to BytesInSizeClass(class_id), + // which is useful in combination with + // ASanStackFrameLayout::ComputeASanStackFrameLayout(). + // + // Note that alignment to 1<= kMaxStackFrameSizeLog (otherwise you + // couldn't store a single frame of that size in the entire stack) + // hence (1<(this) + kFlagsOffset + SizeRequiredForFlags(stack_size_log) + @@ -156,19 +181,21 @@ class FakeStack { private: FakeStack() { } - static const uptr kFlagsOffset = 4096; // This is were the flags begin. + static const uptr kFlagsOffset = 4096; // This is where 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 = ((uptr)1) << kMaxStackFrameSizeLog; uptr hint_position_[kNumberOfSizeClasses]; uptr stack_size_log_; - // a bit is set if something was allocated from the corresponding size class. bool needs_gc_; + // We allocated more memory than needed to ensure the FakeStack (and, by + // extension, each of the fake stack frames) is aligned. We keep track of the + // true start so that we can unmap it. + void *true_start; }; -FakeStack *GetTLSFakeStack(); -void SetTLSFakeStack(FakeStack *fs); +void ResetTLSFakeStack(); } // namespace __asan diff --git a/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp b/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp index 6876be1dca535..a9e5dad91b973 100644 --- a/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp @@ -32,11 +32,11 @@ void EarlySanitizerInit() {} namespace __asan { -// The system already set up the shadow memory for us. -// __sanitizer::GetMaxUserVirtualAddress has already been called by -// AsanInitInternal->InitializeHighMemEnd (asan_rtl.cpp). -// Just do some additional sanity checks here. void InitializeShadowMemory() { + // Explicitly setup shadow here right beforer any of the ShadowBounds members + // are used. + InitShadowBounds(); + if (Verbosity()) PrintAddressSpaceLayout(); diff --git a/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp b/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp index 7ce25497c19eb..cb356e1a1e3b1 100644 --- a/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp @@ -49,24 +49,31 @@ namespace __asan { -#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \ - ASAN_READ_RANGE((ctx), (s), \ - common_flags()->strict_string_checks ? (len) + 1 : (n)) +# define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \ + ASAN_READ_RANGE((ctx), (s), \ + common_flags()->strict_string_checks ? (len) + 1 : (n)) # define ASAN_READ_STRING(ctx, s, n) \ ASAN_READ_STRING_OF_LEN((ctx), (s), internal_strlen(s), (n)) -static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { -#if SANITIZER_INTERCEPT_STRNLEN - if (REAL(strnlen)) { +static inline uptr MaybeRealStrnlen(const char* s, uptr maxlen) { +# if SANITIZER_INTERCEPT_STRNLEN + if (static_cast(REAL(strnlen))) return REAL(strnlen)(s, maxlen); - } -#endif +# endif return internal_strnlen(s, maxlen); } -void SetThreadName(const char *name) { - AsanThread *t = GetCurrentThread(); +static inline uptr MaybeRealWcsnlen(const wchar_t* s, uptr maxlen) { +# if SANITIZER_INTERCEPT_WCSNLEN + if (static_cast(REAL(wcsnlen))) + return REAL(wcsnlen)(s, maxlen); +# endif + return internal_wcsnlen(s, maxlen); +} + +void SetThreadName(const char* name) { + AsanThread* t = GetCurrentThread(); if (t) asanThreadRegistry().SetThreadName(t->tid(), name); } @@ -80,22 +87,22 @@ int OnExit() { return 0; } -} // namespace __asan +} // namespace __asan // ---------------------- Wrappers ---------------- {{{1 using namespace __asan; -DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, usize) -DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) - -#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ - ASAN_INTERCEPT_FUNC_VER(name, ver) -#define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \ - ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) -#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ - ASAN_WRITE_RANGE(ctx, ptr, size) -#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ - ASAN_READ_RANGE(ctx, ptr, size) +DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, usize) +DECLARE_REAL_AND_INTERCEPTOR(void, free, void*) + +# define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ + ASAN_INTERCEPT_FUNC_VER(name, ver) +# define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \ + ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) +# define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ + ASAN_WRITE_RANGE(ctx, ptr, size) +# define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ + ASAN_READ_RANGE(ctx, ptr, size) # define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ ASAN_INTERCEPTOR_ENTER(ctx, func); \ do { \ @@ -107,27 +114,27 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) return REAL(func)(__VA_ARGS__); \ } \ } while (false) -#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ - do { \ - } while (false) -#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ - do { \ - } while (false) -#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ - do { \ - } while (false) -#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ - do { \ - } while (false) -#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name) +# define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ + do { \ + } while (false) +# define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ + do { \ + } while (false) +# define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ + do { \ + } while (false) +# define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ + do { \ + } while (false) +# define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name) // Should be asanThreadRegistry().SetThreadNameByUserId(thread, name) // But asan does not remember UserId's for threads (pthread_t); // and remembers all ever existed threads, so the linear search by UserId // can be slow. -#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ - do { \ - } while (false) -#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) +# define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ + do { \ + } while (false) +# define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) // Strict init-order checking is dlopen-hostile: // https://github.com/google/sanitizers/issues/178 # define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \ @@ -142,7 +149,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) # define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() # define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!AsanInited()) # define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ - if (AsanThread *t = GetCurrentThread()) { \ + if (AsanThread* t = GetCurrentThread()) { \ *begin = t->tls_begin(); \ *end = t->tls_end(); \ } else { \ @@ -150,10 +157,10 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) } template -static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length, +static void* mmap_interceptor(Mmap real_mmap, void* addr, SIZE_T length, int prot, int flags, int fd, OFF64_T offset) { - void *res = real_mmap(addr, length, prot, flags, fd, offset); - if (length && res != (void *)-1) { + void* res = real_mmap(addr, length, prot, flags, fd, offset); + if (length && res != (void*)-1) { const uptr beg = reinterpret_cast(res); DCHECK(IsAligned(beg, GetPageSize())); SIZE_T rounded_length = RoundUpTo(length, GetPageSize()); @@ -165,7 +172,7 @@ static void* mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length, } template -static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) { +static int munmap_interceptor(Munmap real_munmap, void* addr, SIZE_T length) { // We should not tag if munmap fail, but it's to late to tag after // real_munmap, as the pages could be mmaped by another thread. const uptr beg = reinterpret_cast(addr); @@ -178,23 +185,23 @@ static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) { return real_munmap(addr, length); } -# define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \ - fd, offset) \ - do { \ - (void)(ctx); \ - return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \ - } while (false) +# define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \ + fd, offset) \ + do { \ + (void)(ctx); \ + return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \ + } while (false) -# define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \ - do { \ - (void)(ctx); \ - return munmap_interceptor(REAL(munmap), addr, sz); \ - } while (false) +# define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \ + do { \ + (void)(ctx); \ + return munmap_interceptor(REAL(munmap), addr, sz); \ + } while (false) -#if CAN_SANITIZE_LEAKS -#define COMMON_INTERCEPTOR_STRERROR() \ - __lsan::ScopedInterceptorDisabler disabler -#endif +# if CAN_SANITIZE_LEAKS +# define COMMON_INTERCEPTOR_STRERROR() \ + __lsan::ScopedInterceptorDisabler disabler +# endif # define SIGNAL_INTERCEPTOR_ENTER() \ do { \ @@ -206,24 +213,24 @@ static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) { // Syscall interceptors don't have contexts, we don't support suppressions // for them. -#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s) -#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s) -#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ - do { \ - (void)(p); \ - (void)(s); \ - } while (false) -#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ - do { \ - (void)(p); \ - (void)(s); \ - } while (false) -#include "sanitizer_common/sanitizer_common_syscalls.inc" -#include "sanitizer_common/sanitizer_syscalls_netbsd.inc" - -#if ASAN_INTERCEPT_PTHREAD_CREATE -static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { - AsanThread *t = (AsanThread *)arg; +# define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s) +# define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s) +# define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ + do { \ + (void)(p); \ + (void)(s); \ + } while (false) +# define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ + do { \ + (void)(p); \ + (void)(s); \ + } while (false) +# include "sanitizer_common/sanitizer_common_syscalls.inc" +# include "sanitizer_common/sanitizer_syscalls_netbsd.inc" + +# if ASAN_INTERCEPT_PTHREAD_CREATE +static thread_return_t THREAD_CALLING_CONV asan_thread_start(void* arg) { + AsanThread* t = (AsanThread*)arg; SetCurrentThread(t); auto self = GetThreadSelf(); auto args = asanThreadArgRetval().GetArgs(self); @@ -241,8 +248,8 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { return retval; } -INTERCEPTOR(int, pthread_create, void *thread, void *attr, - void *(*start_routine)(void *), void *arg) { +INTERCEPTOR(int, pthread_create, void* thread, void* attr, + void* (*start_routine)(void*), void* arg) { EnsureMainThreadIDIsCorrect(); // Strict init-order checking is thread-hostile. if (flags()->strict_init_order) @@ -262,7 +269,7 @@ INTERCEPTOR(int, pthread_create, void *thread, void *attr, ScopedBlockSignals block(&sigset); # endif - AsanThread *t = AsanThread::Create(sigset, current_tid, &stack, detached); + AsanThread* t = AsanThread::Create(sigset, current_tid, &stack, detached); int result; { @@ -275,7 +282,12 @@ INTERCEPTOR(int, pthread_create, void *thread, void *attr, # endif asanThreadArgRetval().Create(detached, {start_routine, arg}, [&]() -> uptr { result = REAL(pthread_create)(thread, attr, asan_thread_start, t); - return result ? 0 : *(uptr *)(thread); +// AIX pthread_t is unsigned int. +# if SANITIZER_AIX + return result ? 0 : *(unsigned*)(thread); +# else + return result ? 0 : *(uptr*)(thread); +# endif }); } if (result != 0) { @@ -287,7 +299,7 @@ INTERCEPTOR(int, pthread_create, void *thread, void *attr, return result; } -INTERCEPTOR(int, pthread_join, void *thread, void **retval) { +INTERCEPTOR(int, pthread_join, void* thread, void** retval) { int result; asanThreadArgRetval().Join((uptr)thread, [&]() { result = REAL(pthread_join)(thread, retval); @@ -296,7 +308,7 @@ INTERCEPTOR(int, pthread_join, void *thread, void **retval) { return result; } -INTERCEPTOR(int, pthread_detach, void *thread) { +INTERCEPTOR(int, pthread_detach, void* thread) { int result; asanThreadArgRetval().Detach((uptr)thread, [&]() { result = REAL(pthread_detach)(thread); @@ -305,13 +317,13 @@ INTERCEPTOR(int, pthread_detach, void *thread) { return result; } -INTERCEPTOR(void, pthread_exit, void *retval) { +INTERCEPTOR(void, pthread_exit, void* retval) { asanThreadArgRetval().Finish(GetThreadSelf(), retval); REAL(pthread_exit)(retval); } # if ASAN_INTERCEPT_TRYJOIN -INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) { +INTERCEPTOR(int, pthread_tryjoin_np, void* thread, void** ret) { int result; asanThreadArgRetval().Join((uptr)thread, [&]() { result = REAL(pthread_tryjoin_np)(thread, ret); @@ -322,8 +334,8 @@ INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) { # endif # if ASAN_INTERCEPT_TIMEDJOIN -INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, - const struct timespec *abstime) { +INTERCEPTOR(int, pthread_timedjoin_np, void* thread, void** ret, + const struct timespec* abstime) { int result; asanThreadArgRetval().Join((uptr)thread, [&]() { result = REAL(pthread_timedjoin_np)(thread, ret, abstime); @@ -334,9 +346,9 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, # endif DEFINE_INTERNAL_PTHREAD_FUNCTIONS -#endif // ASAN_INTERCEPT_PTHREAD_CREATE +# endif // ASAN_INTERCEPT_PTHREAD_CREATE -#if ASAN_INTERCEPT_SWAPCONTEXT +# if ASAN_INTERCEPT_SWAPCONTEXT static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) { // Only clear if we know the stack. This should be true only for contexts // created with makecontext(). @@ -356,10 +368,10 @@ static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) { // as on other targets. For binary compatibility, the new version uses a // different external name, so we intercept that. # if SANITIZER_SOLARIS && defined(__sparc__) -INTERCEPTOR(void, __makecontext_v2, struct ucontext_t *ucp, void (*func)(), +INTERCEPTOR(void, __makecontext_v2, struct ucontext_t* ucp, void (*func)(), int argc, ...) { # else -INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc, +INTERCEPTOR(void, makecontext, struct ucontext_t* ucp, void (*func)(), int argc, ...) { # endif va_list ap; @@ -386,7 +398,7 @@ INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc, # else REAL(makecontext) # endif - ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64()); + ((struct ucontext_t*)ucp, func, argc, ENUMERATE_ARRAY_64()); # undef ENUMERATE_ARRAY_4 # undef ENUMERATE_ARRAY_16 @@ -396,12 +408,12 @@ INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc, SignContextStack(ucp); } -INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, - struct ucontext_t *ucp) { +INTERCEPTOR(int, swapcontext, struct ucontext_t* oucp, struct ucontext_t* ucp) { static bool reported_warning = false; if (!reported_warning) { - Report("WARNING: ASan doesn't fully support makecontext/swapcontext " - "functions and may produce false positives in some cases!\n"); + Report( + "WARNING: ASan doesn't fully support makecontext/swapcontext " + "functions and may produce false positives in some cases!\n"); reported_warning = true; } // Clear shadow memory for new context (it may share stack @@ -412,7 +424,7 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, # if __has_attribute(__indirect_return__) && \ (defined(__x86_64__) || defined(__i386__)) - int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *) + int (*real_swapcontext)(struct ucontext_t*, struct ucontext_t*) __attribute__((__indirect_return__)) = REAL(swapcontext); int res = real_swapcontext(oucp, ucp); # else @@ -425,112 +437,114 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, ClearShadowMemoryForContextStack(stack, ssize); return res; } -#endif // ASAN_INTERCEPT_SWAPCONTEXT +# endif // ASAN_INTERCEPT_SWAPCONTEXT -#if SANITIZER_NETBSD -#define longjmp __longjmp14 -#define siglongjmp __siglongjmp14 -#endif +# if SANITIZER_NETBSD +# define longjmp __longjmp14 +# define siglongjmp __siglongjmp14 +# endif -INTERCEPTOR(void, longjmp, void *env, int val) { +# if ASAN_INTERCEPT_LONGJMP +INTERCEPTOR(void, longjmp, void* env, int val) { __asan_handle_no_return(); REAL(longjmp)(env, val); } +# endif -#if ASAN_INTERCEPT__LONGJMP -INTERCEPTOR(void, _longjmp, void *env, int val) { +# if ASAN_INTERCEPT__LONGJMP +INTERCEPTOR(void, _longjmp, void* env, int val) { __asan_handle_no_return(); REAL(_longjmp)(env, val); } -#endif +# endif -#if ASAN_INTERCEPT___LONGJMP_CHK -INTERCEPTOR(void, __longjmp_chk, void *env, int val) { +# if ASAN_INTERCEPT___LONGJMP_CHK +INTERCEPTOR(void, __longjmp_chk, void* env, int val) { __asan_handle_no_return(); REAL(__longjmp_chk)(env, val); } -#endif +# endif -#if ASAN_INTERCEPT_SIGLONGJMP -INTERCEPTOR(void, siglongjmp, void *env, int val) { +# if ASAN_INTERCEPT_SIGLONGJMP +INTERCEPTOR(void, siglongjmp, void* env, int val) { __asan_handle_no_return(); REAL(siglongjmp)(env, val); } -#endif +# endif -#if ASAN_INTERCEPT___CXA_THROW -INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { +# if ASAN_INTERCEPT___CXA_THROW +INTERCEPTOR(void, __cxa_throw, void* a, void* b, void* c) { CHECK(REAL(__cxa_throw)); __asan_handle_no_return(); REAL(__cxa_throw)(a, b, c); } -#endif +# endif -#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION -INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) { +# if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION +INTERCEPTOR(void, __cxa_rethrow_primary_exception, void* a) { CHECK(REAL(__cxa_rethrow_primary_exception)); __asan_handle_no_return(); REAL(__cxa_rethrow_primary_exception)(a); } -#endif +# endif -#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION +# if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException, - _Unwind_Exception *object) { + _Unwind_Exception* object) { CHECK(REAL(_Unwind_RaiseException)); __asan_handle_no_return(); return REAL(_Unwind_RaiseException)(object); } -#endif +# endif -#if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION +# if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException, - _Unwind_Exception *object) { + _Unwind_Exception* object) { CHECK(REAL(_Unwind_SjLj_RaiseException)); __asan_handle_no_return(); return REAL(_Unwind_SjLj_RaiseException)(object); } -#endif +# endif -#if ASAN_INTERCEPT_INDEX -# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX -INTERCEPTOR(char*, index, const char *string, int c) - ALIAS(WRAP(strchr)); -# else -# if SANITIZER_APPLE -DECLARE_REAL(char*, index, const char *string, int c) +# if ASAN_INTERCEPT_INDEX +# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX +INTERCEPTOR(char*, index, const char* string, int c) +ALIAS(WRAP(strchr)); +# else +# if SANITIZER_APPLE +DECLARE_REAL(char*, index, const char* string, int c) OVERRIDE_FUNCTION(index, strchr); -# else -DEFINE_REAL(char*, index, const char *string, int c) -# endif -# endif -#endif // ASAN_INTERCEPT_INDEX +# else +DEFINE_REAL(char*, index, const char* string, int c) +# endif +# endif +# endif // ASAN_INTERCEPT_INDEX // For both strcat() and strncat() we need to check the validity of |to| // argument irrespective of the |from| length. - INTERCEPTOR(char *, strcat, char *to, const char *from) { - void *ctx; - ASAN_INTERCEPTOR_ENTER(ctx, strcat); - AsanInitFromRtl(); - if (flags()->replace_str) { - uptr from_length = internal_strlen(from); - ASAN_READ_RANGE(ctx, from, from_length + 1); - uptr to_length = internal_strlen(to); - ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); - ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); - // If the copying actually happens, the |from| string should not overlap - // with the resulting string starting at |to|, which has a length of - // to_length + from_length + 1. - if (from_length > 0) { - CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from, - from_length + 1); - } +INTERCEPTOR(char*, strcat, char* to, const char* from) { + void* ctx; + ASAN_INTERCEPTOR_ENTER(ctx, strcat); + AsanInitFromRtl(); + if (flags()->replace_str) { + uptr from_length = internal_strlen(from); + ASAN_READ_RANGE(ctx, from, from_length + 1); + uptr to_length = internal_strlen(to); + ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); + ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); + // If the copying actually happens, the |from| string should not overlap + // with the resulting string starting at |to|, which has a length of + // to_length + from_length + 1. + if (from_length > 0) { + CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1, from, + from_length + 1); } - return REAL(strcat)(to, from); } + return REAL(strcat)(to, from); +} -INTERCEPTOR(char*, strncat, char *to, const char *from, usize size) { - void *ctx; +INTERCEPTOR(char*, strncat, char* to, const char* from, usize size) { + void* ctx; ASAN_INTERCEPTOR_ENTER(ctx, strncat); AsanInitFromRtl(); if (flags()->replace_str) { @@ -541,15 +555,15 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, usize size) { ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); if (from_length > 0) { - CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1, - from, copy_length); + CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1, from, + copy_length); } } return REAL(strncat)(to, from, size); } -INTERCEPTOR(char *, strcpy, char *to, const char *from) { - void *ctx; +INTERCEPTOR(char*, strcpy, char* to, const char* from) { + void* ctx; ASAN_INTERCEPTOR_ENTER(ctx, strcpy); if constexpr (SANITIZER_APPLE) { // strcpy is called from malloc_default_purgeable_zone() @@ -570,6 +584,20 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) { return REAL(strcpy)(to, from); } +INTERCEPTOR(wchar_t*, wcscpy, wchar_t* to, const wchar_t* from) { + void* ctx; + ASAN_INTERCEPTOR_ENTER(ctx, wcscpy); + if (!TryAsanInitFromRtl()) + return REAL(wcscpy)(to, from); + if (flags()->replace_str) { + uptr size = (internal_wcslen(from) + 1) * sizeof(wchar_t); + CHECK_RANGES_OVERLAP("wcscpy", to, size, from, size); + ASAN_READ_RANGE(ctx, from, size); + ASAN_WRITE_RANGE(ctx, to, size); + } + return REAL(wcscpy)(to, from); +} + // Windows doesn't always define the strdup identifier, // and when it does it's a macro defined to either _strdup // or _strdup_dbg, _strdup_dbg ends up calling _strdup, so @@ -581,8 +609,8 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) { # define strdup _strdup # endif -INTERCEPTOR(char*, strdup, const char *s) { - void *ctx; +INTERCEPTOR(char*, strdup, const char* s) { + void* ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); // Allowing null input is Windows-specific if (SANITIZER_WINDOWS && UNLIKELY(!s)) @@ -594,7 +622,7 @@ INTERCEPTOR(char*, strdup, const char *s) { ASAN_READ_RANGE(ctx, s, length + 1); } GET_STACK_TRACE_MALLOC; - void *new_mem = asan_malloc(length + 1, &stack); + void* new_mem = asan_malloc(length + 1, &stack); if (new_mem) { REAL(memcpy)(new_mem, s, length + 1); } @@ -602,8 +630,8 @@ INTERCEPTOR(char*, strdup, const char *s) { } # if ASAN_INTERCEPT___STRDUP -INTERCEPTOR(char*, __strdup, const char *s) { - void *ctx; +INTERCEPTOR(char*, __strdup, const char* s) { + void* ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); if (UNLIKELY(!TryAsanInitFromRtl())) return internal_strdup(s); @@ -612,16 +640,16 @@ INTERCEPTOR(char*, __strdup, const char *s) { ASAN_READ_RANGE(ctx, s, length + 1); } GET_STACK_TRACE_MALLOC; - void *new_mem = asan_malloc(length + 1, &stack); + void* new_mem = asan_malloc(length + 1, &stack); if (new_mem) { REAL(memcpy)(new_mem, s, length + 1); } return reinterpret_cast(new_mem); } -#endif // ASAN_INTERCEPT___STRDUP +# endif // ASAN_INTERCEPT___STRDUP -INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) { - void *ctx; +INTERCEPTOR(char*, strncpy, char* to, const char* from, usize size) { + void* ctx; ASAN_INTERCEPTOR_ENTER(ctx, strncpy); AsanInitFromRtl(); if (flags()->replace_str) { @@ -633,21 +661,35 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) { return REAL(strncpy)(to, from, size); } +INTERCEPTOR(wchar_t*, wcsncpy, wchar_t* to, const wchar_t* from, uptr size) { + void* ctx; + ASAN_INTERCEPTOR_ENTER(ctx, wcsncpy); + AsanInitFromRtl(); + if (flags()->replace_str) { + uptr from_size = + Min(size, MaybeRealWcsnlen(from, size) + 1) * sizeof(wchar_t); + CHECK_RANGES_OVERLAP("wcsncpy", to, from_size, from, from_size); + ASAN_READ_RANGE(ctx, from, from_size); + ASAN_WRITE_RANGE(ctx, to, size * sizeof(wchar_t)); + } + return REAL(wcsncpy)(to, from, size); +} + template -static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr, - char **endptr, int base) +static ALWAYS_INLINE auto StrtolImpl(void* ctx, Fn real, const char* nptr, + char** endptr, int base) -> decltype(real(nullptr, nullptr, 0)) { if (!flags()->replace_str) return real(nptr, endptr, base); - char *real_endptr; + char* real_endptr; auto res = real(nptr, &real_endptr, base); StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); return res; } # define INTERCEPTOR_STRTO_BASE(ret_type, func) \ - INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \ - void *ctx; \ + INTERCEPTOR(ret_type, func, const char* nptr, char** endptr, int base) { \ + void* ctx; \ ASAN_INTERCEPTOR_ENTER(ctx, func); \ AsanInitFromRtl(); \ return StrtolImpl(ctx, REAL(func), nptr, endptr, base); \ @@ -656,12 +698,12 @@ static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr, INTERCEPTOR_STRTO_BASE(long long, strtoll) # if SANITIZER_WINDOWS -INTERCEPTOR(long, strtol, const char *nptr, char **endptr, int base) { +INTERCEPTOR(long, strtol, const char* nptr, char** endptr, int base) { // REAL(strtol) may be ntdll!strtol, which doesn't set errno. Instead, // call REAL(strtoll) and do the range check ourselves. COMPILER_CHECK(sizeof(long) == sizeof(u32)); - void *ctx; + void* ctx; ASAN_INTERCEPTOR_ENTER(ctx, strtol); AsanInitFromRtl(); @@ -686,8 +728,8 @@ INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol) INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll) # endif -INTERCEPTOR(int, atoi, const char *nptr) { - void *ctx; +INTERCEPTOR(int, atoi, const char* nptr) { + void* ctx; ASAN_INTERCEPTOR_ENTER(ctx, atoi); if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) return REAL(atoi)(nptr); @@ -695,7 +737,7 @@ INTERCEPTOR(int, atoi, const char *nptr) { if (!flags()->replace_str) { return REAL(atoi)(nptr); } - char *real_endptr; + char* real_endptr; // "man atoi" tells that behavior of atoi(nptr) is the same as // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the // parsed integer can't be stored in *long* type (even if it's @@ -706,8 +748,8 @@ INTERCEPTOR(int, atoi, const char *nptr) { return result; } -INTERCEPTOR(long, atol, const char *nptr) { - void *ctx; +INTERCEPTOR(long, atol, const char* nptr) { + void* ctx; ASAN_INTERCEPTOR_ENTER(ctx, atol); if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) return REAL(atol)(nptr); @@ -715,63 +757,63 @@ INTERCEPTOR(long, atol, const char *nptr) { if (!flags()->replace_str) { return REAL(atol)(nptr); } - char *real_endptr; + char* real_endptr; long result = REAL(strtol)(nptr, &real_endptr, 10); FixRealStrtolEndptr(nptr, &real_endptr); ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } -INTERCEPTOR(long long, atoll, const char *nptr) { - void *ctx; +INTERCEPTOR(long long, atoll, const char* nptr) { + void* ctx; ASAN_INTERCEPTOR_ENTER(ctx, atoll); AsanInitFromRtl(); if (!flags()->replace_str) { return REAL(atoll)(nptr); } - char *real_endptr; + char* real_endptr; long long result = REAL(strtoll)(nptr, &real_endptr, 10); FixRealStrtolEndptr(nptr, &real_endptr); ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1); return result; } -#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT -static void AtCxaAtexit(void *unused) { +# if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT +static void AtCxaAtexit(void* unused) { (void)unused; StopInitOrderChecking(); } -#endif +# endif -#if ASAN_INTERCEPT___CXA_ATEXIT -INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, - void *dso_handle) { +# if ASAN_INTERCEPT___CXA_ATEXIT +INTERCEPTOR(int, __cxa_atexit, void (*func)(void*), void* arg, + void* dso_handle) { if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) return REAL(__cxa_atexit)(func, arg, dso_handle); AsanInitFromRtl(); # if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler disabler; -#endif +# endif int res = REAL(__cxa_atexit)(func, arg, dso_handle); REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); return res; } -#endif // ASAN_INTERCEPT___CXA_ATEXIT +# endif // ASAN_INTERCEPT___CXA_ATEXIT -#if ASAN_INTERCEPT_ATEXIT +# if ASAN_INTERCEPT_ATEXIT INTERCEPTOR(int, atexit, void (*func)()) { AsanInitFromRtl(); # if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler disabler; -#endif +# endif // Avoid calling real atexit as it is unreachable on at least on Linux. - int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr); + int res = REAL(__cxa_atexit)((void (*)(void* a))func, nullptr, nullptr); REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); return res; } -#endif +# endif -#if ASAN_INTERCEPT_PTHREAD_ATFORK +# if ASAN_INTERCEPT_PTHREAD_ATFORK extern "C" { extern int _pthread_atfork(void (*prepare)(), void (*parent)(), void (*child)()); @@ -779,19 +821,19 @@ extern int _pthread_atfork(void (*prepare)(), void (*parent)(), INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), void (*child)()) { -#if CAN_SANITIZE_LEAKS +# if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler disabler; -#endif +# endif // REAL(pthread_atfork) cannot be called due to symbol indirections at least // on NetBSD return _pthread_atfork(prepare, parent, child); } -#endif +# endif -#if ASAN_INTERCEPT_VFORK -DEFINE_REAL(int, vfork,) -DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,) -#endif +# if ASAN_INTERCEPT_VFORK +DEFINE_REAL(int, vfork, ) +DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork, ) +# endif // ---------------------- InitializeAsanInterceptors ---------------- {{{1 namespace __asan { @@ -809,12 +851,17 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(strncat); ASAN_INTERCEPT_FUNC(strncpy); ASAN_INTERCEPT_FUNC(strdup); + + // Intercept wcs* functions. + ASAN_INTERCEPT_FUNC(wcscpy); + ASAN_INTERCEPT_FUNC(wcsncpy); + # if ASAN_INTERCEPT___STRDUP ASAN_INTERCEPT_FUNC(__strdup); -#endif -#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX +# endif +# if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX ASAN_INTERCEPT_FUNC(index); -#endif +# endif ASAN_INTERCEPT_FUNC(atoi); ASAN_INTERCEPT_FUNC(atol); @@ -827,7 +874,9 @@ void InitializeAsanInterceptors() { # endif // Intercept jump-related functions. +# if ASAN_INTERCEPT_LONGJMP ASAN_INTERCEPT_FUNC(longjmp); +# endif # if ASAN_INTERCEPT_SWAPCONTEXT ASAN_INTERCEPT_FUNC(swapcontext); @@ -840,38 +889,38 @@ void InitializeAsanInterceptors() { # endif # if ASAN_INTERCEPT__LONGJMP ASAN_INTERCEPT_FUNC(_longjmp); -#endif -#if ASAN_INTERCEPT___LONGJMP_CHK +# endif +# if ASAN_INTERCEPT___LONGJMP_CHK ASAN_INTERCEPT_FUNC(__longjmp_chk); -#endif -#if ASAN_INTERCEPT_SIGLONGJMP +# endif +# if ASAN_INTERCEPT_SIGLONGJMP ASAN_INTERCEPT_FUNC(siglongjmp); -#endif +# endif // Intercept exception handling functions. -#if ASAN_INTERCEPT___CXA_THROW +# if ASAN_INTERCEPT___CXA_THROW ASAN_INTERCEPT_FUNC(__cxa_throw); -#endif -#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION +# endif +# if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception); -#endif +# endif // Indirectly intercept std::rethrow_exception. -#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION +# if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION ASAN_INTERCEPT_FUNC(_Unwind_RaiseException); -#endif +# endif // Indirectly intercept std::rethrow_exception. -#if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION +# if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException); -#endif +# endif // Intercept threading-related functions -#if ASAN_INTERCEPT_PTHREAD_CREATE +# if ASAN_INTERCEPT_PTHREAD_CREATE // TODO: this should probably have an unversioned fallback for newer arches? -#if defined(ASAN_PTHREAD_CREATE_VERSION) +# if defined(ASAN_PTHREAD_CREATE_VERSION) ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION); -#else +# else ASAN_INTERCEPT_FUNC(pthread_create); -#endif +# endif ASAN_INTERCEPT_FUNC(pthread_join); ASAN_INTERCEPT_FUNC(pthread_detach); ASAN_INTERCEPT_FUNC(pthread_exit); @@ -879,28 +928,28 @@ void InitializeAsanInterceptors() { # if ASAN_INTERCEPT_TIMEDJOIN ASAN_INTERCEPT_FUNC(pthread_timedjoin_np); -#endif +# endif -#if ASAN_INTERCEPT_TRYJOIN +# if ASAN_INTERCEPT_TRYJOIN ASAN_INTERCEPT_FUNC(pthread_tryjoin_np); -#endif +# endif // Intercept atexit function. -#if ASAN_INTERCEPT___CXA_ATEXIT +# if ASAN_INTERCEPT___CXA_ATEXIT ASAN_INTERCEPT_FUNC(__cxa_atexit); -#endif +# endif -#if ASAN_INTERCEPT_ATEXIT +# if ASAN_INTERCEPT_ATEXIT ASAN_INTERCEPT_FUNC(atexit); -#endif +# endif -#if ASAN_INTERCEPT_PTHREAD_ATFORK +# if ASAN_INTERCEPT_PTHREAD_ATFORK ASAN_INTERCEPT_FUNC(pthread_atfork); -#endif +# endif -#if ASAN_INTERCEPT_VFORK +# if ASAN_INTERCEPT_VFORK ASAN_INTERCEPT_FUNC(vfork); -#endif +# endif VReport(1, "AddressSanitizer: libc interceptors initialized\n"); } @@ -909,6 +958,6 @@ void InitializeAsanInterceptors() { # pragma pop_macro("strdup") # endif -} // namespace __asan +} // namespace __asan #endif // !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN diff --git a/system/lib/compiler-rt/lib/asan/asan_interceptors.h b/system/lib/compiler-rt/lib/asan/asan_interceptors.h index 3e2386eaf8092..2d806b7df8ffb 100644 --- a/system/lib/compiler-rt/lib/asan/asan_interceptors.h +++ b/system/lib/compiler-rt/lib/asan/asan_interceptors.h @@ -31,105 +31,128 @@ void InitializePlatformInterceptors(); // really defined to replace libc functions. #if !SANITIZER_FUCHSIA +// Sanitizer on AIX is currently unable to retrieve the address +// of the real longjump (or an alternative thereto). +// TODO: Consider intercepting longjmpx on AIX. +# if !SANITIZER_AIX +# define ASAN_INTERCEPT_LONGJMP 1 +# else +# define ASAN_INTERCEPT_LONGJMP 0 +# endif + // Use macro to describe if specific function should be // intercepted on a given platform. -#if !SANITIZER_WINDOWS -# define ASAN_INTERCEPT__LONGJMP 1 -# define ASAN_INTERCEPT_INDEX 1 -# define ASAN_INTERCEPT_PTHREAD_CREATE 1 -#else -# define ASAN_INTERCEPT__LONGJMP 0 -# define ASAN_INTERCEPT_INDEX 0 -# define ASAN_INTERCEPT_PTHREAD_CREATE 0 -#endif - -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS -# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1 -#else -# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0 -#endif - -#if SANITIZER_GLIBC || SANITIZER_SOLARIS -# define ASAN_INTERCEPT_SWAPCONTEXT 1 -#else -# define ASAN_INTERCEPT_SWAPCONTEXT 0 -#endif - -#if !SANITIZER_WINDOWS -# define ASAN_INTERCEPT_SIGLONGJMP 1 -#else -# define ASAN_INTERCEPT_SIGLONGJMP 0 -#endif - -#if SANITIZER_GLIBC -# define ASAN_INTERCEPT___LONGJMP_CHK 1 -#else -# define ASAN_INTERCEPT___LONGJMP_CHK 0 -#endif - -#if ASAN_HAS_EXCEPTIONS && !SANITIZER_SOLARIS && !SANITIZER_NETBSD && \ - (!SANITIZER_WINDOWS || (defined(__MINGW32__) && defined(__i386__))) -# define ASAN_INTERCEPT___CXA_THROW 1 -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 -# if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__)) -# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1 -# else -# define ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 1 -# endif -#else -# define ASAN_INTERCEPT___CXA_THROW 0 -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0 -# define ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 0 -# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 0 -#endif - -#if !SANITIZER_WINDOWS -# define ASAN_INTERCEPT___CXA_ATEXIT 1 -#else -# define ASAN_INTERCEPT___CXA_ATEXIT 0 -#endif - -#if SANITIZER_NETBSD -# define ASAN_INTERCEPT_ATEXIT 1 -#else -# define ASAN_INTERCEPT_ATEXIT 0 -#endif - -#if SANITIZER_GLIBC -# define ASAN_INTERCEPT___STRDUP 1 -#else -# define ASAN_INTERCEPT___STRDUP 0 -#endif - -#if SANITIZER_GLIBC && ASAN_INTERCEPT_PTHREAD_CREATE -# define ASAN_INTERCEPT_TIMEDJOIN 1 -# define ASAN_INTERCEPT_TRYJOIN 1 -#else -# define ASAN_INTERCEPT_TIMEDJOIN 0 -# define ASAN_INTERCEPT_TRYJOIN 0 -#endif - -#if SANITIZER_LINUX && \ - (defined(__arm__) || defined(__aarch64__) || defined(__i386__) || \ - defined(__x86_64__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64) -# define ASAN_INTERCEPT_VFORK 1 -#else -# define ASAN_INTERCEPT_VFORK 0 -#endif - -#if SANITIZER_NETBSD -# define ASAN_INTERCEPT_PTHREAD_ATFORK 1 -#else -# define ASAN_INTERCEPT_PTHREAD_ATFORK 0 -#endif - -DECLARE_REAL(int, memcmp, const void *a1, const void *a2, SIZE_T size) -DECLARE_REAL(char*, strchr, const char *str, int c) -DECLARE_REAL(SIZE_T, strlen, const char *s) -DECLARE_REAL(char*, strncpy, char *to, const char *from, SIZE_T size) -DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen) -DECLARE_REAL(char*, strstr, const char *s1, const char *s2) +# if !SANITIZER_WINDOWS + // Sanitizer on AIX is currently unable to retrieve the address + // of the real _longjump (or an alternative thereto). + // TODO: Consider intercepting _longjmpx on AIX. +# if !SANITIZER_AIX +# define ASAN_INTERCEPT__LONGJMP 1 +# else +# define ASAN_INTERCEPT__LONGJMP 0 +# endif +# define ASAN_INTERCEPT_INDEX 1 +# define ASAN_INTERCEPT_PTHREAD_CREATE 1 +# else +# define ASAN_INTERCEPT__LONGJMP 0 +# define ASAN_INTERCEPT_INDEX 0 +# define ASAN_INTERCEPT_PTHREAD_CREATE 0 +# endif + +# if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS +# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1 +# else +# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0 +# endif + +# if SANITIZER_GLIBC || SANITIZER_SOLARIS +# define ASAN_INTERCEPT_SWAPCONTEXT 1 +# else +# define ASAN_INTERCEPT_SWAPCONTEXT 0 +# endif + +// Sanitizer on AIX is currently unable to retrieve the address +// of the real siglongjump (or an alternative thereto). +// TODO: Consider intercepting sigsetjmpx on AIX. +# if !SANITIZER_WINDOWS && !SANITIZER_AIX +# define ASAN_INTERCEPT_SIGLONGJMP 1 +# else +# define ASAN_INTERCEPT_SIGLONGJMP 0 +# endif + +# if SANITIZER_GLIBC +# define ASAN_INTERCEPT___LONGJMP_CHK 1 +# else +# define ASAN_INTERCEPT___LONGJMP_CHK 0 +# endif + +# if ASAN_HAS_EXCEPTIONS && !SANITIZER_SOLARIS && !SANITIZER_NETBSD && \ + (!SANITIZER_WINDOWS || (defined(__MINGW32__) && defined(__i386__))) +# define ASAN_INTERCEPT___CXA_THROW 1 +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 +# if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__)) +# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1 +# else +# define ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 1 +# endif +# else +# define ASAN_INTERCEPT___CXA_THROW 0 +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0 +# define ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 0 +# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 0 +# endif + +// Clang on AIX neither uses `__cxa_atexit` nor links against a library with +// such. +// TODO: Consider intercepting `atexit` and `unatexit` on AIX. +# if !SANITIZER_WINDOWS && !SANITIZER_AIX +# define ASAN_INTERCEPT___CXA_ATEXIT 1 +# else +# define ASAN_INTERCEPT___CXA_ATEXIT 0 +# endif + +# if SANITIZER_NETBSD +# define ASAN_INTERCEPT_ATEXIT 1 +# else +# define ASAN_INTERCEPT_ATEXIT 0 +# endif + +# if SANITIZER_GLIBC +# define ASAN_INTERCEPT___STRDUP 1 +# else +# define ASAN_INTERCEPT___STRDUP 0 +# endif + +# if SANITIZER_GLIBC && ASAN_INTERCEPT_PTHREAD_CREATE +# define ASAN_INTERCEPT_TIMEDJOIN 1 +# define ASAN_INTERCEPT_TRYJOIN 1 +# else +# define ASAN_INTERCEPT_TIMEDJOIN 0 +# define ASAN_INTERCEPT_TRYJOIN 0 +# endif + +# if SANITIZER_LINUX && \ + (defined(__arm__) || defined(__aarch64__) || defined(__i386__) || \ + defined(__x86_64__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64) +# define ASAN_INTERCEPT_VFORK 1 +# else +# define ASAN_INTERCEPT_VFORK 0 +# endif + +# if SANITIZER_NETBSD +# define ASAN_INTERCEPT_PTHREAD_ATFORK 1 +# else +# define ASAN_INTERCEPT_PTHREAD_ATFORK 0 +# endif + +DECLARE_REAL(int, memcmp, const void* a1, const void* a2, SIZE_T size) +DECLARE_REAL(char*, strchr, const char* str, int c) +DECLARE_REAL(SIZE_T, strlen, const char* s) +DECLARE_REAL(char*, strncpy, char* to, const char* from, SIZE_T size) +DECLARE_REAL(SIZE_T, strnlen, const char* s, SIZE_T maxlen) +DECLARE_REAL(SIZE_T, wcsnlen, const wchar_t* s, SIZE_T maxlen) +DECLARE_REAL(char*, strstr, const char* s1, const char* s2) # if !SANITIZER_APPLE # define ASAN_INTERCEPT_FUNC(name) \ @@ -156,11 +179,11 @@ DECLARE_REAL(char*, strstr, const char *s1, const char *s2) # define ASAN_INTERCEPT_FUNC(name) # endif // SANITIZER_APPLE -#define ASAN_INTERCEPTOR_ENTER(ctx, func) \ - AsanInterceptorContext _ctx = {#func}; \ - ctx = (void *)&_ctx; \ - (void) ctx; -#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name) +# define ASAN_INTERCEPTOR_ENTER(ctx, func) \ + AsanInterceptorContext _ctx = {#func}; \ + ctx = (void*)&_ctx; \ + (void)ctx; +# define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name) #endif // !SANITIZER_FUCHSIA diff --git a/system/lib/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp b/system/lib/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp index 3351121c1862e..3bc2b997420c7 100644 --- a/system/lib/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp @@ -55,8 +55,10 @@ using namespace __asan; if (LIKELY(replace_intrin_cached)) { \ ASAN_READ_RANGE(ctx, from, size); \ ASAN_WRITE_RANGE(ctx, to, size); \ + } else if (UNLIKELY(!AsanInited())) { \ + return internal_memmove(to, from, size); \ } \ - return internal_memmove(to, from, size); \ + return REAL(memmove)(to, from, size); \ } while (0) void *__asan_memcpy(void *to, const void *from, uptr size) { diff --git a/system/lib/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h b/system/lib/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h index 14727a5d665ed..ec988cff51c59 100644 --- a/system/lib/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h +++ b/system/lib/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h @@ -20,6 +20,7 @@ DECLARE_REAL(void *, memcpy, void *to, const void *from, SIZE_T size) DECLARE_REAL(void *, memset, void *block, int c, SIZE_T size) +DECLARE_REAL(void *, memmove, void *to, const void *from, SIZE_T size) namespace __asan { diff --git a/system/lib/compiler-rt/lib/asan/asan_interface.inc b/system/lib/compiler-rt/lib/asan/asan_interface.inc index bfc44b4619623..b465356b1e443 100644 --- a/system/lib/compiler-rt/lib/asan/asan_interface.inc +++ b/system/lib/compiler-rt/lib/asan/asan_interface.inc @@ -165,12 +165,14 @@ INTERFACE_FUNCTION(__asan_store4_noabort) INTERFACE_FUNCTION(__asan_store8_noabort) INTERFACE_FUNCTION(__asan_store16_noabort) INTERFACE_FUNCTION(__asan_storeN_noabort) +INTERFACE_FUNCTION(__asan_suppress_fake_stack) INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone) INTERFACE_FUNCTION(__asan_unpoison_memory_region) INTERFACE_FUNCTION(__asan_unpoison_stack_memory) INTERFACE_FUNCTION(__asan_unregister_globals) INTERFACE_FUNCTION(__asan_unregister_elf_globals) INTERFACE_FUNCTION(__asan_unregister_image_globals) +INTERFACE_FUNCTION(__asan_unsuppress_fake_stack) INTERFACE_FUNCTION(__asan_version_mismatch_check_v8) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) INTERFACE_FUNCTION(__sanitizer_print_stack_trace) diff --git a/system/lib/compiler-rt/lib/asan/asan_mac.cpp b/system/lib/compiler-rt/lib/asan/asan_mac.cpp index be513a03ed5cd..a68e362e07d45 100644 --- a/system/lib/compiler-rt/lib/asan/asan_mac.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_mac.cpp @@ -103,6 +103,8 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) { // dispatch_after() // dispatch_group_async_f() // dispatch_group_async() +// dispatch_apply() +// dispatch_apply_f() // TODO(glider): libdispatch API contains other functions that we don't support // yet. // @@ -128,6 +130,7 @@ typedef void* dispatch_queue_t; typedef void* dispatch_source_t; typedef u64 dispatch_time_t; typedef void (*dispatch_function_t)(void *block); +typedef void (*dispatch_apply_function_t)(void *, size_t); typedef void* (*worker_t)(void *block); typedef unsigned long dispatch_mach_reason; typedef void *dispatch_mach_msg_t; @@ -147,7 +150,11 @@ typedef void (^dispatch_mach_handler_t)(dispatch_mach_reason reason, // A wrapper for the ObjC blocks used to support libdispatch. typedef struct { void *block; - dispatch_function_t func; + union { + dispatch_function_t dispatch_func; + dispatch_apply_function_t dispatch_apply_func; + static_assert(sizeof(dispatch_func) == sizeof(dispatch_apply_func)); + }; u32 parent_tid; } asan_block_context_t; @@ -175,8 +182,8 @@ void asan_dispatch_call_block_and_release(void *block) { block, (void*)pthread_self()); asan_register_worker_thread(context->parent_tid, &stack); // Call the original dispatcher for the block. - context->func(context->block); - asan_free(context, &stack, FROM_MALLOC); + context->dispatch_func(context->block); + asan_free(context, &stack); } } // namespace __asan @@ -191,7 +198,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, asan_block_context_t *asan_ctxt = (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); asan_ctxt->block = ctxt; - asan_ctxt->func = func; + asan_ctxt->dispatch_func = func; asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); return asan_ctxt; } @@ -243,13 +250,34 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, asan_dispatch_call_block_and_release); } -#if !defined(MISSING_BLOCKS_SUPPORT) +extern "C" void asan_dispatch_apply_f_work(void *context, size_t iteration) { + GET_STACK_TRACE_THREAD; + asan_block_context_t *asan_ctxt = (asan_block_context_t *)context; + asan_register_worker_thread(asan_ctxt->parent_tid, &stack); + asan_ctxt->dispatch_apply_func(asan_ctxt->block, iteration); +} + +INTERCEPTOR(void, dispatch_apply_f, size_t iterations, dispatch_queue_t queue, + void *ctxt, dispatch_apply_function_t work) { + GET_STACK_TRACE_THREAD; + asan_block_context_t *asan_ctxt = + (asan_block_context_t *)asan_malloc(sizeof(asan_block_context_t), &stack); + asan_ctxt->block = ctxt; + asan_ctxt->dispatch_apply_func = work; + asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); + REAL(dispatch_apply_f)(iterations, queue, (void *)asan_ctxt, + asan_dispatch_apply_f_work); +} + +# if !defined(MISSING_BLOCKS_SUPPORT) extern "C" { void dispatch_async(dispatch_queue_t dq, void(^work)(void)); void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)); void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)); +void dispatch_apply(size_t iterations, dispatch_queue_t queue, + void (^block)(size_t iteration)); void dispatch_source_set_cancel_handler(dispatch_source_t ds, void(^work)(void)); void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); @@ -332,6 +360,20 @@ INTERCEPTOR(void *, dispatch_mach_create_f, const char *label, }); } -#endif +INTERCEPTOR(void, dispatch_apply, size_t iterations, dispatch_queue_t queue, + void (^block)(size_t iteration)) { + ENABLE_FRAME_POINTER; + int parent_tid = GetCurrentTidOrInvalid(); + + void (^asan_block)(size_t) = ^(size_t iteration) { + GET_STACK_TRACE_THREAD; + asan_register_worker_thread(parent_tid, &stack); + block(iteration); + }; + + REAL(dispatch_apply)(iterations, queue, asan_block); +} + +# endif #endif // SANITIZER_APPLE diff --git a/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp b/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp index 5a81ed3b8435e..12f748bfe2f23 100644 --- a/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp @@ -16,7 +16,7 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \ SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU || \ - SANITIZER_EMSCRIPTEN + SANITIZER_AIX || SANITIZER_EMSCRIPTEN # include "asan_allocator.h" # include "asan_interceptors.h" @@ -50,7 +50,7 @@ INTERCEPTOR(void, free, void *ptr) { if (DlsymAlloc::PointerIsMine(ptr)) return DlsymAlloc::Free(ptr); GET_STACK_TRACE_FREE; - asan_free(ptr, &stack, FROM_MALLOC); + asan_free(ptr, &stack); } #if SANITIZER_INTERCEPT_CFREE @@ -58,7 +58,7 @@ INTERCEPTOR(void, cfree, void *ptr) { if (DlsymAlloc::PointerIsMine(ptr)) return DlsymAlloc::Free(ptr); GET_STACK_TRACE_FREE; - asan_free(ptr, &stack, FROM_MALLOC); + asan_free(ptr, &stack); } #endif // SANITIZER_INTERCEPT_CFREE @@ -94,12 +94,12 @@ INTERCEPTOR(void*, reallocarray, void *ptr, uptr nmemb, uptr size) { #if SANITIZER_INTERCEPT_MEMALIGN INTERCEPTOR(void*, memalign, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; - return asan_memalign(boundary, size, &stack, FROM_MALLOC); + return asan_memalign(boundary, size, &stack); } INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; - return asan_memalign(boundary, size, &stack, FROM_MALLOC); + return asan_memalign(boundary, size, &stack); } #endif // SANITIZER_INTERCEPT_MEMALIGN diff --git a/system/lib/compiler-rt/lib/asan/asan_malloc_mac.cpp b/system/lib/compiler-rt/lib/asan/asan_malloc_mac.cpp index f25d7e1901536..a442bdbbaa4d3 100644 --- a/system/lib/compiler-rt/lib/asan/asan_malloc_mac.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_malloc_mac.cpp @@ -31,7 +31,7 @@ using namespace __asan; # define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock() # define COMMON_MALLOC_MEMALIGN(alignment, size) \ GET_STACK_TRACE_MALLOC; \ - void *p = asan_memalign(alignment, size, &stack, FROM_MALLOC) + void *p = asan_memalign(alignment, size, &stack) # define COMMON_MALLOC_MALLOC(size) \ GET_STACK_TRACE_MALLOC; \ void *p = asan_malloc(size, &stack) @@ -46,10 +46,10 @@ using namespace __asan; int res = asan_posix_memalign(memptr, alignment, size, &stack); # define COMMON_MALLOC_VALLOC(size) \ GET_STACK_TRACE_MALLOC; \ - void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC); + void *p = asan_memalign(GetPageSizeCached(), size, &stack); # define COMMON_MALLOC_FREE(ptr) \ GET_STACK_TRACE_FREE; \ - asan_free(ptr, &stack, FROM_MALLOC); + asan_free(ptr, &stack); # define COMMON_MALLOC_SIZE(ptr) uptr size = asan_mz_size(ptr); # define COMMON_MALLOC_FILL_STATS(zone, stats) \ AsanMallocStats malloc_stats; \ diff --git a/system/lib/compiler-rt/lib/asan/asan_malloc_win.cpp b/system/lib/compiler-rt/lib/asan/asan_malloc_win.cpp index 3278f07219876..ea6f7dfaa08cf 100644 --- a/system/lib/compiler-rt/lib/asan/asan_malloc_win.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_malloc_win.cpp @@ -69,7 +69,7 @@ __declspec(noinline) size_t _msize_base(void *ptr) { return _msize(ptr); } __declspec(noinline) void free(void *ptr) { GET_STACK_TRACE_FREE; - return asan_free(ptr, &stack, FROM_MALLOC); + return asan_free(ptr, &stack); } __declspec(noinline) void _free_dbg(void *ptr, int) { free(ptr); } @@ -252,7 +252,7 @@ INTERCEPTOR_WINAPI(BOOL, HeapFree, HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) { CHECK((HEAP_FREE_UNSUPPORTED_FLAGS & dwFlags) != 0 && "unsupported flags"); } GET_STACK_TRACE_FREE; - asan_free(lpMem, &stack, FROM_MALLOC); + asan_free(lpMem, &stack); return true; } @@ -306,7 +306,7 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc, if (replacement_alloc) { size_t old_size = heapSizeFunc(hHeap, dwFlags, lpMem); if (old_size == ((size_t)0) - 1) { - asan_free(replacement_alloc, &stack, FROM_MALLOC); + asan_free(replacement_alloc, &stack); return nullptr; } REAL(memcpy)(replacement_alloc, lpMem, old_size); @@ -322,6 +322,22 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc, } } + if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY) { + size_t old_usable_size = asan_malloc_usable_size(lpMem, pc, bp); + if (dwBytes == old_usable_size) { + // Nothing to change, return the current pointer. + return lpMem; + } else if (dwBytes >= old_usable_size) { + // Growing with HEAP_REALLOC_IN_PLACE_ONLY is not supported. + return nullptr; + } else { + // Shrinking with HEAP_REALLOC_IN_PLACE_ONLY is not yet supported. + // For now return the current pointer and + // leave the allocation size as it is. + return lpMem; + } + } + if (ownershipState == ASAN && !only_asan_supported_flags) { // Conversion to unsupported flags allocation, // transfer this allocation back to the original allocator. @@ -331,7 +347,7 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc, old_usable_size = asan_malloc_usable_size(lpMem, pc, bp); REAL(memcpy)(replacement_alloc, lpMem, Min(dwBytes, old_usable_size)); - asan_free(lpMem, &stack, FROM_MALLOC); + asan_free(lpMem, &stack); } return replacement_alloc; } @@ -429,7 +445,7 @@ INTERCEPTOR_WINAPI(BOOL, RtlFreeHeap, HANDLE HeapHandle, DWORD Flags, return REAL(RtlFreeHeap)(HeapHandle, Flags, BaseAddress); } GET_STACK_TRACE_FREE; - asan_free(BaseAddress, &stack, FROM_MALLOC); + asan_free(BaseAddress, &stack); return true; } diff --git a/system/lib/compiler-rt/lib/asan/asan_mapping.h b/system/lib/compiler-rt/lib/asan/asan_mapping.h index 1d0f8131338ed..581cea6066571 100644 --- a/system/lib/compiler-rt/lib/asan/asan_mapping.h +++ b/system/lib/compiler-rt/lib/asan/asan_mapping.h @@ -83,18 +83,29 @@ // || `[0x0000000000, 0x0d5554ffff]` || LowMem || // // Default Linux/AArch64 (39-bit VMA) mapping: -// || `[0x2000000000, 0x7fffffffff]` || highmem || -// || `[0x1400000000, 0x1fffffffff]` || highshadow || -// || `[0x1200000000, 0x13ffffffff]` || shadowgap || -// || `[0x1000000000, 0x11ffffffff]` || lowshadow || -// || `[0x0000000000, 0x0fffffffff]` || lowmem || +// TODO: this mapping is ok, but the allocator size is too large on non-Android +// AArch64 platforms (see asan_allocator.h) +// || `[0x2000000000, 0x7fffffffff]` || highmem || 384GB +// || `[0x1400000000, 0x1fffffffff]` || highshadow || 48GB +// || `[0x1200000000, 0x13ffffffff]` || shadowgap || 8GB +// || `[0x1000000000, 0x11ffffffff]` || lowshadow || 8GB +// || `[0x0000000000, 0x0fffffffff]` || lowmem || 64GB // // Default Linux/AArch64 (42-bit VMA) mapping: -// || `[0x10000000000, 0x3ffffffffff]` || highmem || -// || `[0x0a000000000, 0x0ffffffffff]` || highshadow || -// || `[0x09000000000, 0x09fffffffff]` || shadowgap || -// || `[0x08000000000, 0x08fffffffff]` || lowshadow || -// || `[0x00000000000, 0x07fffffffff]` || lowmem || +// TODO: this mapping is ok, but the allocator size is too large on non-Android +// AArch64 platforms (see asan_allocator.h) +// || `[0x09000000000, 0x03ffffffffff]` || highmem || 3520GB +// || `[0x02200000000, 0x008fffffffff]` || highshadow || 440GB +// || `[0x01200000000, 0x0021ffffffff]` || shadowgap || 64GB +// || `[0x01000000000, 0x0011ffffffff]` || lowshadow || 8GB +// || `[0x00000000000, 0x000fffffffff]` || lowmem || 64GB +// +// Default Linux/AArch64 (48-bit VMA) mapping: +// || `[0x201000000000, 0xffffffffffff]` || HighMem || 229312GB +// || `[0x041200000000, 0x200fffffffff]` || HighShadow || 28664GB +// || `[0x001200000000, 0x0411ffffffff]` || ShadowGap || 4096GB +// || `[0x001000000000, 0x0011ffffffff]` || LowShadow || 8GB +// || `[0x000000000000, 0x000fffffffff]` || LowMem || 64GB // // Default Linux/S390 mapping: // || `[0x30000000, 0x7fffffff]` || HighMem || @@ -276,7 +287,7 @@ extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init. # include "asan_mapping_emscripten.h" # else # define MEM_TO_SHADOW(mem) \ - (((mem) >> ASAN_SHADOW_SCALE) + (ASAN_SHADOW_OFFSET)) + ((STRIP_MTE_TAG(mem) >> ASAN_SHADOW_SCALE) + (ASAN_SHADOW_OFFSET)) # define SHADOW_TO_MEM(mem) \ (((mem) - (ASAN_SHADOW_OFFSET)) << (ASAN_SHADOW_SCALE)) @@ -368,6 +379,7 @@ static inline uptr MemToShadowSize(uptr size) { static inline bool AddrIsInMem(uptr a) { PROFILE_ASAN_MAPPING(); + a = STRIP_MTE_TAG(a); return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a) || (flags()->protect_shadow_gap == 0 && AddrIsInShadowGap(a)); } @@ -380,6 +392,7 @@ static inline uptr MemToShadow(uptr p) { static inline bool AddrIsInShadow(uptr a) { PROFILE_ASAN_MAPPING(); + a = STRIP_MTE_TAG(a); return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a); } diff --git a/system/lib/compiler-rt/lib/asan/asan_new_delete.cpp b/system/lib/compiler-rt/lib/asan/asan_new_delete.cpp index 99c7c9938dfb3..d7ed5b570728b 100644 --- a/system/lib/compiler-rt/lib/asan/asan_new_delete.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_new_delete.cpp @@ -60,42 +60,42 @@ enum class align_val_t: size_t {}; // TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM. // For local pool allocation, align to SHADOW_GRANULARITY to match asan // allocator behavior. -#define OPERATOR_NEW_BODY \ - GET_STACK_TRACE_MALLOC; \ - void *res = asan_memalign(0, size, &stack, FROM_NEW); \ - if (UNLIKELY(!res)) \ - ReportOutOfMemory(size, &stack); \ +#define OPERATOR_NEW_BODY \ + GET_STACK_TRACE_MALLOC; \ + void *res = asan_new(size, &stack); \ + if (UNLIKELY(!res)) \ + ReportOutOfMemory(size, &stack); \ return res #define OPERATOR_NEW_BODY_NOTHROW \ GET_STACK_TRACE_MALLOC; \ - return asan_memalign(0, size, &stack, FROM_NEW) -#define OPERATOR_NEW_BODY_ARRAY \ - GET_STACK_TRACE_MALLOC; \ - void *res = asan_memalign(0, size, &stack, FROM_NEW_BR); \ - if (UNLIKELY(!res)) \ - ReportOutOfMemory(size, &stack); \ + return asan_new(size, &stack) +#define OPERATOR_NEW_BODY_ARRAY \ + GET_STACK_TRACE_MALLOC; \ + void *res = asan_new_array(size, &stack); \ + if (UNLIKELY(!res)) \ + ReportOutOfMemory(size, &stack); \ return res #define OPERATOR_NEW_BODY_ARRAY_NOTHROW \ GET_STACK_TRACE_MALLOC; \ - return asan_memalign(0, size, &stack, FROM_NEW_BR) -#define OPERATOR_NEW_BODY_ALIGN \ - GET_STACK_TRACE_MALLOC; \ - void *res = asan_memalign((uptr)align, size, &stack, FROM_NEW); \ - if (UNLIKELY(!res)) \ - ReportOutOfMemory(size, &stack); \ + return asan_new_array(size, &stack) +#define OPERATOR_NEW_BODY_ALIGN \ + GET_STACK_TRACE_MALLOC; \ + void *res = asan_new_aligned(size, static_cast(align), &stack); \ + if (UNLIKELY(!res)) \ + ReportOutOfMemory(size, &stack); \ return res #define OPERATOR_NEW_BODY_ALIGN_NOTHROW \ GET_STACK_TRACE_MALLOC; \ - return asan_memalign((uptr)align, size, &stack, FROM_NEW) -#define OPERATOR_NEW_BODY_ALIGN_ARRAY \ - GET_STACK_TRACE_MALLOC; \ - void *res = asan_memalign((uptr)align, size, &stack, FROM_NEW_BR); \ - if (UNLIKELY(!res)) \ - ReportOutOfMemory(size, &stack); \ + return asan_new_aligned(size, static_cast(align), &stack) +#define OPERATOR_NEW_BODY_ALIGN_ARRAY \ + GET_STACK_TRACE_MALLOC; \ + void *res = asan_new_array_aligned(size, static_cast(align), &stack); \ + if (UNLIKELY(!res)) \ + ReportOutOfMemory(size, &stack); \ return res #define OPERATOR_NEW_BODY_ALIGN_ARRAY_NOTHROW \ GET_STACK_TRACE_MALLOC; \ - return asan_memalign((uptr)align, size, &stack, FROM_NEW_BR) + return asan_new_array_aligned(size, static_cast(align), &stack) // On OS X it's not enough to just provide our own 'operator new' and // 'operator delete' implementations, because they're going to be in the @@ -149,28 +149,28 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { #define OPERATOR_DELETE_BODY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, 0, 0, &stack, FROM_NEW) + asan_delete(ptr, &stack) #define OPERATOR_DELETE_BODY_ARRAY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, 0, 0, &stack, FROM_NEW_BR) + asan_delete_array(ptr, &stack) #define OPERATOR_DELETE_BODY_ALIGN \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, 0, static_cast(align), &stack, FROM_NEW) + asan_delete_aligned(ptr, static_cast(align), &stack) #define OPERATOR_DELETE_BODY_ALIGN_ARRAY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, 0, static_cast(align), &stack, FROM_NEW_BR) + asan_delete_array_aligned(ptr, static_cast(align), &stack) #define OPERATOR_DELETE_BODY_SIZE \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, size, 0, &stack, FROM_NEW) + asan_delete_sized(ptr, size, &stack) #define OPERATOR_DELETE_BODY_SIZE_ARRAY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, size, 0, &stack, FROM_NEW_BR) + asan_delete_array_sized(ptr, size, &stack) #define OPERATOR_DELETE_BODY_SIZE_ALIGN \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, size, static_cast(align), &stack, FROM_NEW) + asan_delete_sized_aligned(ptr, size, static_cast(align), &stack) #define OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, size, static_cast(align), &stack, FROM_NEW_BR) + asan_delete_array_sized_aligned(ptr, size, static_cast(align), &stack) #if !SANITIZER_APPLE CXX_OPERATOR_ATTRIBUTE diff --git a/system/lib/compiler-rt/lib/asan/asan_posix.cpp b/system/lib/compiler-rt/lib/asan/asan_posix.cpp index ca691059cfae1..8efd87029fb09 100644 --- a/system/lib/compiler-rt/lib/asan/asan_posix.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_posix.cpp @@ -184,7 +184,7 @@ static void AfterFork(bool fork_child) { void InstallAtForkHandler() { # if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE || \ - (SANITIZER_LINUX && SANITIZER_SPARC) || SANITIZER_HAIKU + (SANITIZER_LINUX && SANITIZER_SPARC) || SANITIZER_HAIKU || SANITIZER_AIX // While other Linux targets use clone in internal_fork which doesn't // trigger pthread_atfork handlers, Linux/sparc64 uses __fork, causing a // hang. diff --git a/system/lib/compiler-rt/lib/asan/asan_thread.cpp b/system/lib/compiler-rt/lib/asan/asan_thread.cpp index 58671efc960b0..caaf587927b37 100644 --- a/system/lib/compiler-rt/lib/asan/asan_thread.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_thread.cpp @@ -165,7 +165,7 @@ void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, if (fake_stack_save) *fake_stack_save = fake_stack_; fake_stack_ = nullptr; - SetTLSFakeStack(nullptr); + ResetTLSFakeStack(); // 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()); @@ -179,8 +179,8 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old, } if (fake_stack_save) { - SetTLSFakeStack(fake_stack_save); fake_stack_ = fake_stack_save; + ResetTLSFakeStack(); } if (bottom_old) @@ -244,7 +244,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { Max(stack_size_log, static_cast(flags()->min_uar_stack_size_log)); fake_stack_ = FakeStack::Create(stack_size_log); DCHECK_EQ(GetCurrentThread(), this); - SetTLSFakeStack(fake_stack_); + ResetTLSFakeStack(); return fake_stack_; } return nullptr; @@ -253,6 +253,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { void AsanThread::Init(const InitOptions *options) { DCHECK_NE(tid(), kInvalidTid); next_stack_top_ = next_stack_bottom_ = 0; + fake_stack_suppression_counter_ = 0; atomic_store(&stack_switching_, false, memory_order_release); CHECK_EQ(this->stack_size(), 0U); SetThreadStackAndTls(options); @@ -284,7 +285,7 @@ void AsanThread::Init(const InitOptions *options) { // asan_fuchsia.c definies CreateMainThread and SetThreadStackAndTls. #if !SANITIZER_FUCHSIA -void AsanThread::ThreadStart(tid_t os_id) { +void AsanThread::ThreadStart(ThreadID os_id) { Init(); asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr); @@ -408,6 +409,19 @@ bool AsanThread::AddrIsInStack(uptr addr) { return addr >= bounds.bottom && addr < bounds.top; } +void AsanThread::SuppressFakeStack() { + ++fake_stack_suppression_counter_; + ResetTLSFakeStack(); +} + +void AsanThread::UnsuppressFakeStack() { + if (fake_stack_suppression_counter_ == 0) { + Report("ERROR: Unmatched call to __asan_unsuppress_fake_stack().\n"); + Die(); + } + --fake_stack_suppression_counter_; +} + static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, void *addr) { AsanThreadContext *tctx = static_cast(tctx_base); @@ -473,7 +487,7 @@ void EnsureMainThreadIDIsCorrect() { context->os_id = GetTid(); } -__asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) { +__asan::AsanThread *GetAsanThreadByOsIDLocked(ThreadID os_id) { __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); if (!context) @@ -501,7 +515,7 @@ static ThreadRegistry *GetAsanThreadRegistryLocked() { void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); } -bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, +bool GetThreadRangesLocked(ThreadID os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); @@ -520,7 +534,7 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches) {} -void GetThreadExtraStackRangesLocked(tid_t os_id, +void GetThreadExtraStackRangesLocked(ThreadID os_id, InternalMmapVector *ranges) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); if (!t) @@ -550,11 +564,11 @@ void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) { __asan::asanThreadArgRetval().GetAllPtrsLocked(ptrs); } -void GetRunningThreadsLocked(InternalMmapVector *threads) { +void GetRunningThreadsLocked(InternalMmapVector *threads) { GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked( [](ThreadContextBase *tctx, void *threads) { if (tctx->status == ThreadStatusRunning) - reinterpret_cast *>(threads)->push_back( + reinterpret_cast *>(threads)->push_back( tctx->os_id); }, threads); diff --git a/system/lib/compiler-rt/lib/asan/asan_thread.h b/system/lib/compiler-rt/lib/asan/asan_thread.h index ad9e03d68fe96..e9ca6b6a59016 100644 --- a/system/lib/compiler-rt/lib/asan/asan_thread.h +++ b/system/lib/compiler-rt/lib/asan/asan_thread.h @@ -75,7 +75,7 @@ class AsanThread { struct InitOptions; void Init(const InitOptions *options = nullptr); - void ThreadStart(tid_t os_id); + void ThreadStart(ThreadID os_id); thread_return_t RunThread(); uptr stack_top(); @@ -104,7 +104,7 @@ class AsanThread { if (!fake_stack_) return; FakeStack *t = fake_stack_; fake_stack_ = nullptr; - SetTLSFakeStack(nullptr); + ResetTLSFakeStack(); t->Destroy(tid); } @@ -144,6 +144,12 @@ class AsanThread { GetStartData(&data, sizeof(data)); } + bool IsFakeStackSuppressed() const { + return fake_stack_suppression_counter_ > 0; + } + void SuppressFakeStack(); + void UnsuppressFakeStack(); + private: // NOTE: There is no AsanThread constructor. It is allocated // via mmap() and *must* be valid in zero-initialized state. @@ -179,6 +185,7 @@ class AsanThread { DTLS *dtls_; FakeStack *fake_stack_; + int fake_stack_suppression_counter_; AsanThreadLocalMallocStorage malloc_storage_; AsanStats stats_; bool unwinding_; diff --git a/system/lib/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp b/system/lib/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp index 4a69b66574039..46e0e90738f24 100644 --- a/system/lib/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp @@ -63,6 +63,10 @@ INTERCEPT_LIBRARY_FUNCTION_ASAN(strpbrk); INTERCEPT_LIBRARY_FUNCTION_ASAN(strspn); INTERCEPT_LIBRARY_FUNCTION_ASAN(strstr); INTERCEPT_LIBRARY_FUNCTION_ASAN(strtok); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcscat); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcscpy); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsncat); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsncpy); INTERCEPT_LIBRARY_FUNCTION_ASAN(wcslen); INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsnlen); diff --git a/system/lib/compiler-rt/lib/builtins/assembly.h b/system/lib/compiler-rt/lib/builtins/assembly.h index d7db7d8189457..2eddbf468c149 100644 --- a/system/lib/compiler-rt/lib/builtins/assembly.h +++ b/system/lib/compiler-rt/lib/builtins/assembly.h @@ -14,7 +14,7 @@ #ifndef COMPILERRT_ASSEMBLY_H #define COMPILERRT_ASSEMBLY_H -#if defined(__linux__) && defined(__CET__) +#ifdef __CET__ #if __has_include() #include #endif @@ -71,9 +71,24 @@ #endif +#if defined(__aarch64__) && defined(__ELF__) && \ + defined(COMPILER_RT_EXECUTE_ONLY_CODE) +// The assembler always creates an implicit '.text' section with default flags +// (SHF_ALLOC | SHF_EXECINSTR), which is incompatible with the execute-only +// '.text' section we want to create here because of the missing +// SHF_AARCH64_PURECODE section flag. To solve this, we use 'unique,0' to +// differentiate the two sections. The output will therefore have two separate +// sections named '.text', where code will be placed into the execute-only +// '.text' section, and the implicitly-created one will be empty. +#define TEXT_SECTION \ + .section .text,"axy",@progbits,unique,0 +#else +#define TEXT_SECTION \ + .text +#endif + #if defined(__arm__) || defined(__aarch64__) || defined(__arm64ec__) #define FUNC_ALIGN \ - .text SEPARATOR \ .balign 16 SEPARATOR #else #define FUNC_ALIGN @@ -255,6 +270,7 @@ #endif #define DEFINE_COMPILERRT_FUNCTION(name) \ + TEXT_SECTION SEPARATOR \ DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ @@ -264,6 +280,7 @@ FUNC_SYMBOL(SYMBOL_NAME(name)): #define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ + TEXT_SECTION SEPARATOR \ DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ @@ -273,6 +290,7 @@ FUNC_SYMBOL(SYMBOL_NAME(name)): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ + TEXT_SECTION SEPARATOR \ DEFINE_CODE_STATE \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ @@ -282,6 +300,7 @@ FUNC_SYMBOL(SYMBOL_NAME(name)): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ + TEXT_SECTION SEPARATOR \ DEFINE_CODE_STATE \ .globl FUNC_SYMBOL(name) SEPARATOR \ SYMBOL_IS_FUNC(name) SEPARATOR \ @@ -290,6 +309,7 @@ FUNC_SYMBOL(name): #define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \ + TEXT_SECTION SEPARATOR \ DEFINE_CODE_STATE \ FUNC_ALIGN \ .globl FUNC_SYMBOL(name) SEPARATOR \ @@ -304,7 +324,7 @@ .globl FUNC_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \ - .set FUNC_SYMBOL(SYMBOL_NAME(name)), FUNC_SYMBOL(target) SEPARATOR + .set FUNC_SYMBOL(SYMBOL_NAME(name)), FUNC_SYMBOL(SYMBOL_NAME(target)) SEPARATOR #if defined(__ARM_EABI__) #define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \ @@ -337,4 +357,9 @@ #endif #endif +#if defined(__ASSEMBLER__) && (defined(__i386__) || defined(__amd64__)) && \ + !defined(__arm64ec__) +.att_syntax +#endif + #endif // COMPILERRT_ASSEMBLY_H diff --git a/system/lib/compiler-rt/lib/builtins/crtbegin.c b/system/lib/compiler-rt/lib/builtins/crtbegin.c index 447474bd0b692..8b5f98fdd04ed 100644 --- a/system/lib/compiler-rt/lib/builtins/crtbegin.c +++ b/system/lib/compiler-rt/lib/builtins/crtbegin.c @@ -19,7 +19,7 @@ __attribute__((visibility("hidden"))) void *__dso_handle = &__dso_handle; #ifdef EH_USE_FRAME_REGISTRY -__extension__ static void *__EH_FRAME_LIST__[] +__extension__ static void *const __EH_FRAME_LIST__[] __attribute__((section(".eh_frame"), aligned(sizeof(void *)))) = {}; extern void __register_frame_info(const void *, void *) __attribute__((weak)); diff --git a/system/lib/compiler-rt/lib/builtins/gcc_personality_v0.c b/system/lib/compiler-rt/lib/builtins/gcc_personality_v0.c index ef63a5fb83472..6d92a7b248f3c 100644 --- a/system/lib/compiler-rt/lib/builtins/gcc_personality_v0.c +++ b/system/lib/compiler-rt/lib/builtins/gcc_personality_v0.c @@ -30,6 +30,58 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT, _Unwind_Personality_Fn); #endif +#ifndef __has_feature +#define __has_feature(__feature) 0 +#endif + +#if __has_feature(ptrauth_calls) +#include + +// `__ptrauth_restricted_intptr` is a feature of apple clang that predates +// support for direct application of `__ptrauth` to integer types. This +// guard is necessary to support compilation with those compiler. +#if __has_feature(ptrauth_restricted_intptr_qualifier) +#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \ + discriminator) \ + __ptrauth_restricted_intptr(key, addressDiscriminated, discriminator) +#else +#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \ + discriminator) \ + __ptrauth(key, addressDiscriminated, discriminator) +#endif +#else +#define __ptrauth_gcc_personality_intptr(...) +#endif + +#define __ptrauth_gcc_personality_func_key ptrauth_key_function_pointer + +// ptrauth_string_discriminator("__gcc_personality_v0'funcStart") == 0xDFEB +#define __ptrauth_gcc_personality_func_start \ + __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \ + 0xDFEB) + +// ptrauth_string_discriminator("__gcc_personality_v0'start") == 0x52DC +#define __ptrauth_gcc_personality_start \ + __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \ + 0x52DC) + +// ptrauth_string_discriminator("__gcc_personality_v0'length") == 0xFFF7 +#define __ptrauth_gcc_personality_length \ + __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \ + 0xFFF7) + +// ptrauth_string_discriminator("__gcc_personality_v0'landingPadOffset") == +// 0x6498 +#define __ptrauth_gcc_personality_lpoffset \ + __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \ + 0x6498) + +// ptrauth_string_discriminator("__gcc_personality_v0'landingPad") == 0xA134 +#define __ptrauth_gcc_personality_lpad_disc 0xA134 +#define __ptrauth_gcc_personality_lpad \ + __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \ + __ptrauth_gcc_personality_lpad_disc) + // Pointer encodings documented at: // http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html @@ -205,7 +257,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0( return continueUnwind(exceptionObject, context); uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1; - uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context); + uintptr_t __ptrauth_gcc_personality_func_start funcStart = + (uintptr_t)_Unwind_GetRegionStart(context); uintptr_t pcOffset = pc - funcStart; // Parse LSDA header. @@ -224,11 +277,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0( const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength; const uint8_t *p = callSiteTableStart; while (p < callSiteTableEnd) { - uintptr_t start = readEncodedPointer(&p, callSiteEncoding); - size_t length = readEncodedPointer(&p, callSiteEncoding); - size_t landingPad = readEncodedPointer(&p, callSiteEncoding); + uintptr_t __ptrauth_gcc_personality_start start = + readEncodedPointer(&p, callSiteEncoding); + size_t __ptrauth_gcc_personality_length length = + readEncodedPointer(&p, callSiteEncoding); + size_t __ptrauth_gcc_personality_lpoffset landingPadOffset = + readEncodedPointer(&p, callSiteEncoding); readULEB128(&p); // action value not used for C code - if (landingPad == 0) + if (landingPadOffset == 0) continue; // no landing pad for this entry if ((start <= pcOffset) && (pcOffset < (start + length))) { // Found landing pad for the PC. @@ -238,7 +294,24 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0( _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)exceptionObject); _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0); - _Unwind_SetIP(context, (funcStart + landingPad)); + size_t __ptrauth_gcc_personality_lpad landingPad = + funcStart + landingPadOffset; +#if __has_feature(ptrauth_calls) + uintptr_t stackPointer = _Unwind_GetGR(context, -2); + const uintptr_t existingDiscriminator = ptrauth_blend_discriminator( + &landingPad, __ptrauth_gcc_personality_lpad_disc); + // newIP is authenticated as if it were qualified with a pseudo qualifier + // along the lines of: + // __ptrauth(ptrauth_key_return_address, , 0) + // where the stack pointer is used in place of the strict storage + // address. + uintptr_t newIP = (uintptr_t)ptrauth_auth_and_resign( + *(void **)&landingPad, __ptrauth_gcc_personality_func_key, + existingDiscriminator, ptrauth_key_return_address, stackPointer); + _Unwind_SetIP(context, newIP); +#else + _Unwind_SetIP(context, landingPad); +#endif return _URC_INSTALL_CONTEXT; } } diff --git a/system/lib/compiler-rt/lib/builtins/int_to_fp_impl.inc b/system/lib/compiler-rt/lib/builtins/int_to_fp_impl.inc index 51f76fd76d803..11736ed7aafc8 100644 --- a/system/lib/compiler-rt/lib/builtins/int_to_fp_impl.inc +++ b/system/lib/compiler-rt/lib/builtins/int_to_fp_impl.inc @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// // -// Thsi file implements a generic conversion from an integer type to an -// IEEE-754 floating point type, allowing a common implementation to be hsared +// This file implements a generic conversion from an integer type to an +// IEEE-754 floating point type, allowing a common implementation to be shared // without copy and paste. // //===----------------------------------------------------------------------===// @@ -49,15 +49,15 @@ static __inline dst_t __floatXiYf__(src_t a) { a |= (a & 4) != 0; // Or P into R ++a; // round - this step may add a significant bit a >>= 2; // dump Q and R - // a is now rounded to dstMantDig or dstMantDig+1 bits + // `a` is now rounded to dstMantDig or dstMantDig+1 bits if (a & ((usrc_t)1 << dstMantDig)) { a >>= 1; ++e; } - // a is now rounded to dstMantDig bits + // `a` is now rounded to dstMantDig bits } else { a <<= (dstMantDig - sd); - // a is now rounded to dstMantDig bits + // `a` is now rounded to dstMantDig bits } const int dstBits = sizeof(dst_t) * CHAR_BIT; const dst_rep_t dstSignMask = DST_REP_C(1) << (dstBits - 1); diff --git a/system/lib/compiler-rt/lib/interception/interception_aix.cpp b/system/lib/compiler-rt/lib/interception/interception_aix.cpp index 953bbad96eb47..a6cc4f7498f44 100644 --- a/system/lib/compiler-rt/lib/interception/interception_aix.cpp +++ b/system/lib/compiler-rt/lib/interception/interception_aix.cpp @@ -17,16 +17,61 @@ #if SANITIZER_AIX # include // for dlsym() +# include // for size_t + +# if SANITIZER_WORDSIZE == 64 +# define STRCPY_STR "___strcpy64" +# define MEMCPY_STR "___memcpy64" +# define MEMMOVE_STR "___memmove64" +# else +# define STRCPY_STR "___strcpy" +# define MEMCPY_STR "___memcpy" +# define MEMMOVE_STR "___memmove" +# endif namespace __interception { -static void *GetFuncAddr(const char *name, uptr wrapper_addr) { - // AIX dlsym can only defect the functions that are exported, so - // on AIX, we can not intercept some basic functions like memcpy. +// These symbols cannot be used for indirect calls. +char* ___strcpy(char*, const char*) __asm__(STRCPY_STR); +char* ___memcpy(char*, const char*, size_t) __asm__(MEMCPY_STR); +char* ___memmove(char*, const char*, size_t) __asm__(MEMMOVE_STR); + +static char* real_strcpy_wrapper(char* s1, const char* s2) { + return (char*)___strcpy(s1, s2); +} + +static char* real_memcpy_wrapper(char* s1, const char* s2, size_t n) { + return (char*)___memcpy(s1, s2, n); +} + +static char* real_memmove_wrapper(char* s1, const char* s2, size_t n) { + return (char*)___memmove(s1, s2, n); +} + +static void* GetFuncAddr(const char* name, uptr wrapper_addr) { // FIXME: if we are going to ship dynamic asan library, we may need to search // all the loaded modules with RTLD_DEFAULT if RTLD_NEXT failed. void *addr = dlsym(RTLD_NEXT, name); + // AIX dlsym can only detect functions that are exported, so + // some basic functions like memcpy return null. In this case, we fall back + // to a corresponding internal libc symbol (for example, ___memcpy) if it's + // available and, otherwise, to the internal sanitizer function. + if (!addr) { + if (internal_strcmp(name, "strcpy") == 0) + addr = (void*)real_strcpy_wrapper; + else if (internal_strcmp(name, "strncpy") == 0) + addr = (void*)internal_strncpy; + else if (internal_strcmp(name, "strcat") == 0) + addr = (void*)internal_strcat; + else if (internal_strcmp(name, "strncat") == 0) + addr = (void*)internal_strncat; + else if (internal_strcmp(name, "memcpy") == 0) + addr = (void*)real_memcpy_wrapper; + else if (internal_strcmp(name, "memmove") == 0) + addr = (void*)real_memmove_wrapper; + } + // In case `name' is not loaded, dlsym ends up finding the actual wrapper. // We don't want to intercept the wrapper and have it point to itself. if ((uptr)addr == wrapper_addr) diff --git a/system/lib/compiler-rt/lib/interception/interception_win.cpp b/system/lib/compiler-rt/lib/interception/interception_win.cpp index 246a22c56c31a..856872425117a 100644 --- a/system/lib/compiler-rt/lib/interception/interception_win.cpp +++ b/system/lib/compiler-rt/lib/interception/interception_win.cpp @@ -646,6 +646,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0xC033: // 33 C0 : xor eax, eax case 0xC933: // 33 C9 : xor ecx, ecx case 0xD233: // 33 D2 : xor edx, edx + case 0xFF33: // 33 FF : xor edi, edi case 0x9066: // 66 90 : xchg %ax,%ax (Two-byte NOP) case 0xDB84: // 84 DB : test bl,bl case 0xC084: // 84 C0 : test al,al @@ -764,6 +765,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { switch (0x00FFFFFF & *(u32 *)address) { case 0x10b70f: // 0f b7 10 : movzx edx, WORD PTR [rax] + case 0x02b70f: // 0f b7 02 : movzx eax, WORD PTR [rdx] case 0xc00b4d: // 4d 0b c0 : or r8, r8 case 0xc03345: // 45 33 c0 : xor r8d, r8d case 0xc08548: // 48 85 c0 : test rax, rax @@ -799,6 +801,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0xc9854d: // 4d 85 c9 : test r9, r9 case 0xc98b4c: // 4c 8b c9 : mov r9, rcx case 0xd12948: // 48 29 d1 : sub rcx, rdx + case 0xc22b4c: // 4c 2b c2 : sub r8, rdx case 0xca2b48: // 48 2b ca : sub rcx, rdx case 0xca3b48: // 48 3b ca : cmp rcx, rdx case 0xd12b48: // 48 2b d1 : sub rdx, rcx @@ -813,6 +816,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0xd9f748: // 48 f7 d9 : neg rcx case 0xc03145: // 45 31 c0 : xor r8d,r8d case 0xc93145: // 45 31 c9 : xor r9d,r9d + case 0xd23345: // 45 33 d2 : xor r10d, r10d case 0xdb3345: // 45 33 db : xor r11d, r11d case 0xc08445: // 45 84 c0 : test r8b,r8b case 0xd28445: // 45 84 d2 : test r10b,r10b diff --git a/system/lib/compiler-rt/lib/lsan/lsan_allocator.h b/system/lib/compiler-rt/lib/lsan/lsan_allocator.h index 556b9f56a4a4a..2d0ea0b46fe0e 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_allocator.h +++ b/system/lib/compiler-rt/lib/lsan/lsan_allocator.h @@ -93,6 +93,10 @@ using LSanSizeClassMap = DefaultSizeClassMap; const uptr kAllocatorSpace = 0x600000000000ULL; const uptr kAllocatorSize = 0x40000000000ULL; // 4T. using LSanSizeClassMap = DefaultSizeClassMap; +# elif SANITIZER_ANDROID && defined(__aarch64__) +const uptr kAllocatorSpace = 0x3000000000ULL; +const uptr kAllocatorSize = 0x2000000000ULL; +using LSanSizeClassMap = VeryCompactSizeClassMap; # else const uptr kAllocatorSpace = 0x500000000000ULL; const uptr kAllocatorSize = 0x40000000000ULL; // 4T. diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common.cpp index b24e140417320..114710fb500ac 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_common.cpp @@ -442,7 +442,7 @@ void ScanExtraStackRanges(const InternalMmapVector &ranges, # if SANITIZER_FUCHSIA // Fuchsia handles all threads together with its own callback. -static void ProcessThreads(SuspendedThreadsList const &, Frontier *, tid_t, +static void ProcessThreads(SuspendedThreadsList const &, Frontier *, ThreadID, uptr) {} # else @@ -478,7 +478,7 @@ static void ProcessThreadRegistry(Frontier *frontier) { // Scans thread data (stacks and TLS) for heap pointers. template -static void ProcessThread(tid_t os_id, uptr sp, +static void ProcessThread(ThreadID os_id, uptr sp, const InternalMmapVector ®isters, InternalMmapVector &extra_ranges, Frontier *frontier, Accessor &accessor) { @@ -589,16 +589,16 @@ static void ProcessThread(tid_t os_id, uptr sp, } static void ProcessThreads(SuspendedThreadsList const &suspended_threads, - Frontier *frontier, tid_t caller_tid, + Frontier *frontier, ThreadID caller_tid, uptr caller_sp) { - InternalMmapVector done_threads; + InternalMmapVector done_threads; InternalMmapVector registers; InternalMmapVector extra_ranges; for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) { registers.clear(); extra_ranges.clear(); - const tid_t os_id = suspended_threads.GetThreadID(i); + const ThreadID os_id = suspended_threads.GetThreadID(i); uptr sp = 0; PtraceRegistersStatus have_registers = suspended_threads.GetRegistersAndSP(i, ®isters, &sp); @@ -622,10 +622,10 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, if (flags()->use_detached) { CopyMemoryAccessor accessor; - InternalMmapVector known_threads; + InternalMmapVector known_threads; GetRunningThreadsLocked(&known_threads); Sort(done_threads.data(), done_threads.size()); - for (tid_t os_id : known_threads) { + for (ThreadID os_id : known_threads) { registers.clear(); extra_ranges.clear(); @@ -750,7 +750,7 @@ static void CollectIgnoredCb(uptr chunk, void *arg) { // Sets the appropriate tag on each chunk. static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads, - Frontier *frontier, tid_t caller_tid, + Frontier *frontier, ThreadID caller_tid, uptr caller_sp) { const InternalMmapVector &suppressed_stacks = GetSuppressionContext()->GetSortedSuppressedStacks(); @@ -828,13 +828,13 @@ static bool ReportUnsuspendedThreads(const SuspendedThreadsList &) { static bool ReportUnsuspendedThreads( const SuspendedThreadsList &suspended_threads) { - InternalMmapVector threads(suspended_threads.ThreadCount()); + InternalMmapVector threads(suspended_threads.ThreadCount()); for (uptr i = 0; i < suspended_threads.ThreadCount(); ++i) threads[i] = suspended_threads.GetThreadID(i); Sort(threads.data(), threads.size()); - InternalMmapVector known_threads; + InternalMmapVector known_threads; GetRunningThreadsLocked(&known_threads); bool succeded = true; @@ -844,7 +844,7 @@ static bool ReportUnsuspendedThreads( succeded = false; Report( "Running thread %zu was not suspended. False leaks are possible.\n", - os_id); + (usize)os_id); } } return succeded; diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common.h b/system/lib/compiler-rt/lib/lsan/lsan_common.h index 40465334947d3..8b66a82e7d5e7 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common.h +++ b/system/lib/compiler-rt/lib/lsan/lsan_common.h @@ -102,15 +102,15 @@ void UnlockThreads() SANITIZER_NO_THREAD_SAFETY_ANALYSIS; // where leak checking is initiated from a non-main thread). void EnsureMainThreadIDIsCorrect(); -bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, +bool GetThreadRangesLocked(ThreadID os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls); void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches); void GetThreadExtraStackRangesLocked(InternalMmapVector *ranges); -void GetThreadExtraStackRangesLocked(tid_t os_id, +void GetThreadExtraStackRangesLocked(ThreadID os_id, InternalMmapVector *ranges); void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs); -void GetRunningThreadsLocked(InternalMmapVector *threads); +void GetRunningThreadsLocked(InternalMmapVector *threads); void PrintThreads(); //// -------------------------------------------------------------------------- @@ -247,7 +247,7 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier); struct CheckForLeaksParam { Frontier frontier; LeakedChunks leaks; - tid_t caller_tid; + ThreadID caller_tid; uptr caller_sp; bool success = false; }; diff --git a/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp b/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp index f0b8bb6f28412..836fcb5b473ee 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -397,12 +397,12 @@ INTERCEPTOR(void, _lwp_exit) { #endif #if SANITIZER_INTERCEPT_THR_EXIT -INTERCEPTOR(void, thr_exit, tid_t *state) { +INTERCEPTOR(void, thr_exit, ThreadID *state) { ENSURE_LSAN_INITED; ThreadFinish(); REAL(thr_exit)(state); } -#define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit) +# define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit) #else #define LSAN_MAYBE_INTERCEPT_THR_EXIT #endif diff --git a/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp b/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp index 593000b9eef99..ae1590b9d6fc1 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp @@ -48,7 +48,7 @@ void ThreadContext::OnStarted(void *arg) { dtls_ = args->dtls; } -void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) { +void ThreadStart(u32 tid, ThreadID os_id, ThreadType thread_type) { OnStartedArgs args; GetThreadStackAndTls(tid == kMainTid, &args.stack_begin, &args.stack_end, &args.tls_begin, &args.tls_end); @@ -57,7 +57,7 @@ void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) { ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args); } -bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, +bool GetThreadRangesLocked(ThreadID os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls) { ThreadContext *context = static_cast( diff --git a/system/lib/compiler-rt/lib/lsan/lsan_posix.h b/system/lib/compiler-rt/lib/lsan/lsan_posix.h index b1265f233f363..7587a07c40f61 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_posix.h +++ b/system/lib/compiler-rt/lib/lsan/lsan_posix.h @@ -41,7 +41,7 @@ class ThreadContext final : public ThreadContextLsanBase { DTLS *dtls_ = nullptr; }; -void ThreadStart(u32 tid, tid_t os_id, +void ThreadStart(u32 tid, ThreadID os_id, ThreadType thread_type = ThreadType::Regular); } // namespace __lsan diff --git a/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp b/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp index cfc55b771a2b8..311179314938b 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp @@ -69,7 +69,7 @@ u32 ThreadCreate(u32 parent_tid, bool detached, void *arg) { return thread_registry->CreateThread(0, detached, parent_tid, arg); } -void ThreadContextLsanBase::ThreadStart(u32 tid, tid_t os_id, +void ThreadContextLsanBase::ThreadStart(u32 tid, ThreadID os_id, ThreadType thread_type, void *arg) { thread_registry->StartThread(tid, os_id, thread_type, arg); } @@ -83,7 +83,7 @@ void EnsureMainThreadIDIsCorrect() { ///// Interface to the common LSan module. ///// -void GetThreadExtraStackRangesLocked(tid_t os_id, +void GetThreadExtraStackRangesLocked(ThreadID os_id, InternalMmapVector *ranges) {} void GetThreadExtraStackRangesLocked(InternalMmapVector *ranges) {} @@ -102,11 +102,11 @@ ThreadRegistry *GetLsanThreadRegistryLocked() { return thread_registry; } -void GetRunningThreadsLocked(InternalMmapVector *threads) { +void GetRunningThreadsLocked(InternalMmapVector *threads) { GetLsanThreadRegistryLocked()->RunCallbackForEachThreadLocked( [](ThreadContextBase *tctx, void *threads) { if (tctx->status == ThreadStatusRunning) { - reinterpret_cast *>(threads)->push_back( + reinterpret_cast *>(threads)->push_back( tctx->os_id); } }, diff --git a/system/lib/compiler-rt/lib/lsan/lsan_thread.h b/system/lib/compiler-rt/lib/lsan/lsan_thread.h index 222066ee93cd9..b7262a9ef3b26 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_thread.h +++ b/system/lib/compiler-rt/lib/lsan/lsan_thread.h @@ -30,7 +30,7 @@ class ThreadContextLsanBase : public ThreadContextBase { uptr cache_end() { return cache_end_; } // The argument is passed on to the subclass's OnStarted member function. - static void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type, + static void ThreadStart(u32 tid, ThreadID os_id, ThreadType thread_type, void *onstarted_arg); protected: diff --git a/system/lib/compiler-rt/lib/profile/GCDAProfiling.c b/system/lib/compiler-rt/lib/profile/GCDAProfiling.c index ac01805e70adc..523ade5eafc15 100644 --- a/system/lib/compiler-rt/lib/profile/GCDAProfiling.c +++ b/system/lib/compiler-rt/lib/profile/GCDAProfiling.c @@ -21,6 +21,11 @@ #if !defined(__Fuchsia__) +#if defined(__linux__) +// For fdopen() +#define _DEFAULT_SOURCE +#endif + #include #include #include diff --git a/system/lib/compiler-rt/lib/profile/InstrProfiling.c b/system/lib/compiler-rt/lib/profile/InstrProfiling.c index da04d8ebdec95..d59ec78ad3296 100644 --- a/system/lib/compiler-rt/lib/profile/InstrProfiling.c +++ b/system/lib/compiler-rt/lib/profile/InstrProfiling.c @@ -10,8 +10,6 @@ // with freestanding compilation. See `darwin_add_builtin_libraries`. #include -#include -#include #include #include "InstrProfiling.h" diff --git a/system/lib/compiler-rt/lib/profile/InstrProfiling.h b/system/lib/compiler-rt/lib/profile/InstrProfiling.h index 8791d5aa5dd70..187ef55ef3784 100644 --- a/system/lib/compiler-rt/lib/profile/InstrProfiling.h +++ b/system/lib/compiler-rt/lib/profile/InstrProfiling.h @@ -10,7 +10,10 @@ #define PROFILE_INSTRPROFILING_H_ #include "InstrProfilingPort.h" +#include +#ifndef COMPILER_RT_PROFILE_BAREMETAL #include +#endif // Make sure __LLVM_INSTR_PROFILE_GENERATE is always defined before // including instr_prof_interface.h so the interface functions are @@ -200,7 +203,9 @@ int __llvm_profile_write_file(void); * copying the old profile file to new profile file and this function is usually * used when the proess doesn't have permission to open file. */ +#ifndef COMPILER_RT_PROFILE_BAREMETAL int __llvm_profile_set_file_object(FILE *File, int EnableMerge); +#endif /*! \brief Register to write instrumentation data to file at exit. */ int __llvm_profile_register_write_file_atexit(void); diff --git a/system/lib/compiler-rt/lib/profile/InstrProfilingFile.c b/system/lib/compiler-rt/lib/profile/InstrProfilingFile.c index 354f21b786151..71127b05aafb8 100644 --- a/system/lib/compiler-rt/lib/profile/InstrProfilingFile.c +++ b/system/lib/compiler-rt/lib/profile/InstrProfilingFile.c @@ -8,6 +8,11 @@ #if !defined(__Fuchsia__) +#if defined(__linux__) +// For fileno(), ftruncate(), getpagesize(), setenv() +#define _DEFAULT_SOURCE +#endif + #include #include #include diff --git a/system/lib/compiler-rt/lib/profile/InstrProfilingMerge.c b/system/lib/compiler-rt/lib/profile/InstrProfilingMerge.c index 92721c4fd55ea..681abda0188ac 100644 --- a/system/lib/compiler-rt/lib/profile/InstrProfilingMerge.c +++ b/system/lib/compiler-rt/lib/profile/InstrProfilingMerge.c @@ -11,7 +11,6 @@ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" -#include "InstrProfilingUtil.h" #define INSTR_PROF_VALUE_PROF_DATA #include "profile/InstrProfData.inc" diff --git a/system/lib/compiler-rt/lib/profile/InstrProfilingMergeFile.c b/system/lib/compiler-rt/lib/profile/InstrProfilingMergeFile.c index 8923ba21cc580..d8fe1f6677950 100644 --- a/system/lib/compiler-rt/lib/profile/InstrProfilingMergeFile.c +++ b/system/lib/compiler-rt/lib/profile/InstrProfilingMergeFile.c @@ -13,7 +13,6 @@ #include "InstrProfiling.h" #include "InstrProfilingInternal.h" -#include "InstrProfilingUtil.h" #define INSTR_PROF_VALUE_PROF_DATA #include "profile/InstrProfData.inc" diff --git a/system/lib/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/system/lib/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c index 558b7fc8cad62..acdb222004fd4 100644 --- a/system/lib/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c +++ b/system/lib/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c @@ -6,16 +6,33 @@ |* \*===----------------------------------------------------------------------===*/ +// This file defines profile data symbols for ELF, wasm, XCOFF. It assumes +// __start_ and __stop_ symbols for profile data point at the beginning and +// end of the sections in question. (This is technically a linker feature, +// not a file format feature, but linkers for these targets support it.) +// +// MachO (MacOS/iOS) and PE-COFF (Windows) have a similar support, but the +// identifiers are different, so the support is in separate files. +// +// Support for targets which don't have linker support is in +// InstrProfilingPlatformOther.c. +// +// This file also contains code to extract ELF build IDs from the ELF file, +// to identify the build which generated the file. + #if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ (defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) || \ - defined(_AIX) || defined(__wasm__) || defined(__HAIKU__) + defined(_AIX) || defined(__wasm__) || defined(__HAIKU__) || \ + defined(COMPILER_RT_PROFILE_BAREMETAL) -#if !defined(_AIX) && !defined(__wasm__) +#if !defined(_AIX) && !defined(__wasm__) && \ + !defined(COMPILER_RT_PROFILE_BAREMETAL) +// Includes for non-baremetal ELF targets, used to output build IDs. #include #include -#endif #include #include +#endif #include "InstrProfiling.h" #include "InstrProfilingInternal.h" diff --git a/system/lib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c b/system/lib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c index 19414ab78b3be..f5d1c74f10115 100644 --- a/system/lib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c +++ b/system/lib/compiler-rt/lib/profile/InstrProfilingPlatformOther.c @@ -6,10 +6,18 @@ |* \*===----------------------------------------------------------------------===*/ +// This file defines a fallback implementation to compute the locations of +// profile data sections, for targets that don't have linker support. No +// commonly used targets use this codepath. +// +// This implementation expects the compiler instrumentation pass to define a +// constructor in each file which calls into this file. + #if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) && \ !defined(__Fuchsia__) && !(defined(__sun__) && defined(__svr4__)) && \ !defined(__NetBSD__) && !defined(_WIN32) && !defined(_AIX) && \ - !defined(__wasm__) && !defined(__HAIKU__) + !defined(__wasm__) && !defined(__HAIKU__) && \ + !defined(COMPILER_RT_PROFILE_BAREMETAL) #include #include diff --git a/system/lib/compiler-rt/lib/profile/InstrProfilingPort.h b/system/lib/compiler-rt/lib/profile/InstrProfilingPort.h index a1eaa83375289..d238cc8c3ea51 100644 --- a/system/lib/compiler-rt/lib/profile/InstrProfilingPort.h +++ b/system/lib/compiler-rt/lib/profile/InstrProfilingPort.h @@ -117,9 +117,17 @@ static inline size_t getpagesize(void) { return S.dwPageSize; } #else /* defined(_WIN32) */ +#ifndef COMPILER_RT_PROFILE_BAREMETAL #include +#endif #endif /* defined(_WIN32) */ +#ifdef COMPILER_RT_PROFILE_BAREMETAL +// Baremetal doesn't support logging +#define PROF_ERR(Format, ...) +#define PROF_WARN(Format, ...) +#define PROF_NOTE(Format, ...) +#else #define PROF_ERR(Format, ...) \ fprintf(stderr, "LLVM Profile Error: " Format, __VA_ARGS__); @@ -128,6 +136,7 @@ static inline size_t getpagesize(void) { #define PROF_NOTE(Format, ...) \ fprintf(stderr, "LLVM Profile Note: " Format, __VA_ARGS__); +#endif /* COMPILER_RT_PROFILE_BAREMETAL */ #ifndef MAP_FILE #define MAP_FILE 0 @@ -137,16 +146,6 @@ static inline size_t getpagesize(void) { #define O_BINARY 0 #endif -#if defined(__FreeBSD__) - -#include -#include - -#else /* defined(__FreeBSD__) */ - -#include #include -#endif /* defined(__FreeBSD__) && defined(__i386__) */ - #endif /* PROFILE_INSTRPROFILING_PORT_H_ */ diff --git a/system/lib/compiler-rt/lib/profile/InstrProfilingUtil.c b/system/lib/compiler-rt/lib/profile/InstrProfilingUtil.c index 0fae91cfb8950..a9d9df813764b 100644 --- a/system/lib/compiler-rt/lib/profile/InstrProfilingUtil.c +++ b/system/lib/compiler-rt/lib/profile/InstrProfilingUtil.c @@ -12,6 +12,11 @@ #include #include "WindowsMMap.h" #else +#if defined(__linux__) +// For fdopen(), fileno(), getpagesize(), madvise() +#define _DEFAULT_SOURCE +#endif + #include #include #include diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h index 602b197c42ae3..0faf9b3c151a4 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -288,6 +288,7 @@ class SizeClassAllocator32 { uptr ComputeRegionId(uptr mem) const { if (SANITIZER_SIGN_EXTENDED_ADDRESSES) mem &= (kSpaceSize - 1); + mem -= kSpaceBeg; const uptr res = mem >> kRegionSizeLog; CHECK_LT(res, kNumPossibleRegions); return res; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h index 51ac1b6ae4975..b39eb1538cbcd 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -113,6 +113,24 @@ class SizeClassAllocator64 { // ~(uptr)0. void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) { uptr TotalSpaceSize = kSpaceSize + AdditionalSize(); + + uptr MaxAddr = GetMaxUserVirtualAddress(); + // VReport does not call the sanitizer allocator. + VReport(3, "Max user virtual address: 0x%zx\n", MaxAddr); + VReport(3, "Total space size for primary allocator: 0x%zx\n", + TotalSpaceSize); + // TODO: revise the check if we ever configure sanitizers to deliberately + // map beyond the 2**48 barrier (note that Linux pretends the VMA is + // limited to 48-bit for backwards compatibility, but allows apps to + // explicitly specify an address beyond that). + if (heap_start + TotalSpaceSize >= MaxAddr) { + // We can't easily adjust the requested heap size, because kSpaceSize is + // const (for optimization) and used throughout the code. + VReport(0, "Error: heap size %zx exceeds max user virtual address %zx\n", + TotalSpaceSize, MaxAddr); + VReport( + 0, "Try using a kernel that allows a larger virtual address space\n"); + } PremappedHeap = heap_start != 0; if (PremappedHeap) { CHECK(!kUsingConstantSpaceBeg); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 120c2861c1ac0..515a7c9cdf60f 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -78,8 +78,8 @@ uptr GetMmapGranularity(); uptr GetMaxVirtualAddress(); uptr GetMaxUserVirtualAddress(); // Threads -tid_t GetTid(); -int TgKill(pid_t pid, tid_t tid, int sig); +ThreadID GetTid(); +int TgKill(pid_t pid, ThreadID tid, int sig); uptr GetThreadSelf(); void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr *stack_bottom); @@ -390,6 +390,9 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid, void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); +bool IsSignalHandlerFromSanitizer(int signum); +bool SetSignalHandlerFromSanitizer(int signum, bool new_state); + // Construct a one-line string: // SUMMARY: SanitizerToolName: error_message // and pass it to __sanitizer_report_error_summary. @@ -484,6 +487,13 @@ inline uptr Log2(uptr x) { return LeastSignificantSetBitIndex(x); } +inline bool IntervalsAreSeparate(uptr start1, uptr end1, uptr start2, + uptr end2) { + CHECK_LE(start1, end1); + CHECK_LE(start2, end2); + return (end1 < start2) || (end2 < start1); +} + // Don't use std::min, std::max or std::swap, to minimize dependency // on libstdc++. template @@ -734,6 +744,7 @@ enum ModuleArch { kModuleArchARMV7S, kModuleArchARMV7K, kModuleArchARM64, + kModuleArchARM64E, kModuleArchLoongArch64, kModuleArchRISCV64, kModuleArchHexagon @@ -807,6 +818,8 @@ inline const char *ModuleArchToString(ModuleArch arch) { return "armv7k"; case kModuleArchARM64: return "arm64"; + case kModuleArchARM64E: + return "arm64e"; case kModuleArchLoongArch64: return "loongarch64"; case kModuleArchRISCV64: diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 2d6cf7fc3282f..b10ce7fa44afc 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -1285,8 +1285,34 @@ INTERCEPTOR(int, puts, char *s) { #endif #if SANITIZER_INTERCEPT_PRCTL -INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) { + +# if defined(__aarch64__) +// https://llvm.org/docs/PointerAuth.html +// AArch64 is currently the only architecture with full PAC support. +// Avoid adding PAC instructions to prevent crashes caused by +// prctl(PR_PAC_RESET_KEYS, ...). Since PR_PAC_RESET_KEYS resets the +// authentication key, using the old key afterward will lead to a crash. + +# if defined(__ARM_FEATURE_BTI_DEFAULT) +# define BRANCH_PROTECTION_ATTRIBUTE \ + __attribute__((target("branch-protection=bti"))) +# else +# define BRANCH_PROTECTION_ATTRIBUTE \ + __attribute__((target("branch-protection=none"))) +# endif + +# define PRCTL_INTERCEPTOR(ret_type, func, ...) \ + DEFINE_REAL(ret_type, func, __VA_ARGS__) \ + DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ + extern "C" INTERCEPTOR_ATTRIBUTE BRANCH_PROTECTION_ATTRIBUTE ret_type \ + WRAP(func)(__VA_ARGS__) + +# else +# define PRCTL_INTERCEPTOR INTERCEPTOR +# endif + +PRCTL_INTERCEPTOR(int, prctl, int option, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5); static const int PR_SET_NAME = 15; @@ -1300,7 +1326,7 @@ INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, static const int PR_SET_SECCOMP = 22; static const int SECCOMP_MODE_FILTER = 2; # endif - if (option == PR_SET_VMA && arg2 == 0UL) { + if (option == PR_SET_VMA && arg2 == 0UL && arg5 != 0UL) { char *name = (char *)arg5; COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1); } @@ -1326,7 +1352,7 @@ INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, } return res; } -#define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl) +# define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl) #else #define INIT_PRCTL #endif // SANITIZER_INTERCEPT_PRCTL diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc index 521fc116f2888..ee3ac723e3669 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc @@ -143,6 +143,12 @@ struct sanitizer_kernel_sockaddr { char sa_data[14]; }; +struct sanitizer_kernel_open_how { + u64 flags; + u64 mode; + u64 resolve; +}; + // Real sigset size is always passed as a syscall argument. // Declare it "void" to catch sizeof(kernel_sigset_t). typedef void kernel_sigset_t; @@ -2843,6 +2849,18 @@ PRE_SYSCALL(openat)(long dfd, const void *filename, long flags, long mode) { POST_SYSCALL(openat) (long res, long dfd, const void *filename, long flags, long mode) {} +PRE_SYSCALL(openat2)(long dfd, const void* filename, + const sanitizer_kernel_open_how* how, uptr howlen) { + if (filename) + PRE_READ(filename, __sanitizer::internal_strlen((const char*)filename) + 1); + + if (how) + PRE_READ(how, howlen); +} + +POST_SYSCALL(openat2)(long res, long dfd, const void* filename, + const sanitizer_kernel_open_how* how, uptr howlen) {} + PRE_SYSCALL(newfstatat) (long dfd, const void *filename, void *statbuf, long flag) { if (filename) diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp index 9236a458cdb0e..e8f219b941159 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp @@ -36,9 +36,17 @@ void RawWrite(const char *buffer) { void ReportFile::ReopenIfNecessary() { mu->CheckLocked(); - if (fd == kStdoutFd || fd == kStderrFd) return; - uptr pid = internal_getpid(); + if (fallbackToStderrActive && fd_pid != pid) { + // If fallbackToStderrActive is set then we fellback to stderr. If this is a + // new process, mark fd as invalid so we attempt to open again. + CHECK_EQ(fd, kStderrFd); + fd = kInvalidFd; + fallbackToStderrActive = false; + } + if (fd == kStdoutFd || fd == kStderrFd) + return; + // If in tracer, use the parent's file. if (pid == stoptheworld_tracer_pid) pid = stoptheworld_tracer_ppid; @@ -48,8 +56,7 @@ void ReportFile::ReopenIfNecessary() { // process, close it now. if (fd_pid == pid) return; - else - CloseFile(fd); + CloseFile(fd); } const char *exe_name = GetProcessName(); @@ -65,18 +72,24 @@ void ReportFile::ReopenIfNecessary() { error_t err; fd = OpenFile(full_path, WrOnly, &err); if (fd == kInvalidFd) { - const char *ErrorMsgPrefix = "ERROR: Can't open file: "; + bool fallback = common_flags()->log_fallback_to_stderr; + const char *ErrorMsgPrefix = + fallback ? "WARNING: Can't open file, falling back to stderr: " + : "ERROR: Can't open file: "; WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); char errmsg[100]; internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)\n", err); WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg)); - Die(); + if (!fallback) + Die(); + fallbackToStderrActive = true; + fd = kStderrFd; } fd_pid = pid; } -static void RecursiveCreateParentDirs(char *path) { +static void RecursiveCreateParentDirs(char *path, fd_t &fd) { if (path[0] == '\0') return; for (int i = 1; path[i] != '\0'; ++i) { @@ -85,12 +98,19 @@ static void RecursiveCreateParentDirs(char *path) { continue; path[i] = '\0'; if (!DirExists(path) && !CreateDir(path)) { - const char *ErrorMsgPrefix = "ERROR: Can't create directory: "; + bool fallback = common_flags()->log_fallback_to_stderr; + const char *ErrorMsgPrefix = + fallback ? "WARNING: Can't create directory, falling back to stderr: " + : "ERROR: Can't create directory: "; WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); WriteToFile(kStderrFd, path, internal_strlen(path)); const char *ErrorMsgSuffix = "\n"; WriteToFile(kStderrFd, ErrorMsgSuffix, internal_strlen(ErrorMsgSuffix)); - Die(); + if (!fallback) + Die(); + path[i] = save; + fd = kStderrFd; + return; } path[i] = save; } @@ -108,6 +128,9 @@ static void ParseAndSetPath(const char *pattern, char *dest, CHECK(dest); CHECK_GE(dest_size, 1); dest[0] = '\0'; + // Return empty string if empty string was passed + if (internal_strlen(pattern) == 0) + return; uptr next_substr_start_idx = 0; for (uptr i = 0; i < internal_strlen(pattern) - 1; i++) { if (pattern[i] != '%') @@ -161,12 +184,17 @@ void ReportFile::SetReportPath(const char *path) { if (path) { uptr len = internal_strlen(path); if (len > sizeof(path_prefix) - 100) { - const char *message = "ERROR: Path is too long: "; + bool fallback = common_flags()->log_fallback_to_stderr; + const char *message = + fallback ? "WARNING: Path is too long, falling back to stderr: " + : "ERROR: Path is too long: "; WriteToFile(kStderrFd, message, internal_strlen(message)); WriteToFile(kStderrFd, path, 8); message = "...\n"; WriteToFile(kStderrFd, message, internal_strlen(message)); - Die(); + if (!fallback) + Die(); + path = "stderr"; } } @@ -180,7 +208,7 @@ void ReportFile::SetReportPath(const char *path) { fd = kStdoutFd; } else { ParseAndSetPath(path, path_prefix, kMaxPathLength); - RecursiveCreateParentDirs(path_prefix); + RecursiveCreateParentDirs(path_prefix, fd); } } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h index bef2c842d9f24..b3a5fed922da9 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h @@ -43,6 +43,9 @@ struct ReportFile { // PID of the process that opened fd. If a fork() occurs, // the PID of child will be different from fd_pid. uptr fd_pid; + // Set to true if the last attempt to open the logfile failed, perhaps due to + // permission errors + bool fallbackToStderrActive = false; private: void ReopenIfNecessary(); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc index c1e3530618c20..5f449907f6011 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc @@ -65,6 +65,8 @@ COMMON_FLAG( bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_APPLE, "Write all sanitizer output to syslog in addition to other means of " "logging.") +COMMON_FLAG(bool, log_fallback_to_stderr, false, + "When set, fallback to stderr if we are unable to open log path.") COMMON_FLAG( int, verbosity, 0, "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") @@ -111,6 +113,11 @@ COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes, COMMON_FLAG(bool, allow_user_segv_handler, true, "Deprecated. True has no effect, use handle_sigbus=1. If false, " "handle_*=1 will be upgraded to handle_*=2.") +COMMON_FLAG(bool, cloak_sanitizer_signal_handlers, false, + "If set, signal/sigaction will pretend that sanitizers did not " + "preinstall any signal handlers. If the user subsequently installs " + "a signal handler, this will disable cloaking for the respective " + "signal.") COMMON_FLAG(bool, use_sigaltstack, true, "If set, uses alternate stack for signal handling.") COMMON_FLAG(bool, detect_deadlocks, true, diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp index 1ca50eb186a34..3c61b60802996 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp @@ -14,6 +14,7 @@ #include "sanitizer_fuchsia.h" #if SANITIZER_FUCHSIA +# include # include # include # include @@ -68,7 +69,7 @@ int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); } uptr GetThreadSelf() { return reinterpret_cast(thrd_current()); } -tid_t GetTid() { return GetThreadSelf(); } +ThreadID GetTid() { return GetThreadSelf(); } void Abort() { abort(); } @@ -117,11 +118,37 @@ uptr GetMmapGranularity() { return _zx_system_get_page_size(); } sanitizer_shadow_bounds_t ShadowBounds; +// Any sanitizer that utilizes shadow should explicitly call whenever it's +// appropriate for that sanitizer to reference shadow bounds. For ASan, this is +// done in `InitializeShadowMemory` and for HWASan, this is done in +// `InitShadow`. void InitShadowBounds() { ShadowBounds = __sanitizer_shadow_bounds(); } +// TODO(leonardchan): It's not immediately clear from a user perspective if +// `GetMaxUserVirtualAddress` should be called exatly once on runtime startup +// or can be called multiple times. Currently it looks like most instances of +// `GetMaxUserVirtualAddress` are meant to be called once, but if someone +// decides to call this multiple times in the future, we should have a separate +// function that's ok to call multiple times. Ideally we would just invoke this +// syscall once. Also for Fuchsia, this syscall technically gets invoked twice +// since `__sanitizer_shadow_bounds` also invokes this syscall under the hood. uptr GetMaxUserVirtualAddress() { - InitShadowBounds(); - return ShadowBounds.memory_limit - 1; + zx_info_vmar_t info; + zx_status_t status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, + &info, sizeof(info), NULL, NULL); + CHECK_EQ(status, ZX_OK); + + // Find the top of the accessible address space. + uintptr_t top = info.base + info.len; + + // Round it up to a power-of-two size. There may be some pages at + // the top that can't actually be mapped, but for purposes of the + // the shadow, we'll pretend they could be. + int bit = (sizeof(uintptr_t) * CHAR_BIT) - __builtin_clzl(top); + if (top != (uintptr_t)1 << bit) + top = (uintptr_t)1 << (bit + 1); + + return top - 1; } uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_haiku.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_haiku.cpp index 7cf2437d5b755..7c114417560e5 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_haiku.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_haiku.cpp @@ -231,12 +231,12 @@ uptr internal_execve(const char *filename, char *const argv[], } # if 0 -tid_t GetTid() { +ThreadID GetTid() { DEFINE__REAL(int, _lwp_self); return _REAL(_lwp_self); } -int TgKill(pid_t pid, tid_t tid, int sig) { +int TgKill(pid_t pid, ThreadID tid, int sig) { DEFINE__REAL(int, _lwp_kill, int a, int b); (void)pid; return _REAL(_lwp_kill, tid, sig); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h index fff60c96f632f..c719e2a8ef600 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -209,7 +209,7 @@ typedef long ssize; typedef sptr ssize; #endif -typedef u64 tid_t; +typedef u64 ThreadID; // ----------- ATTENTION ------------- // This header should NOT include any other headers to avoid portability issues. diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp index 9318066afed20..ece768ec8dab6 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp @@ -190,6 +190,14 @@ uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { return dstlen + srclen; } +char* internal_strcat(char* dst, const char* src) { + uptr len = internal_strlen(dst); + uptr i; + for (i = 0; src[i]; i++) dst[len + i] = src[i]; + dst[len + i] = 0; + return dst; +} + char *internal_strncat(char *dst, const char *src, uptr n) { uptr len = internal_strlen(dst); uptr i; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h index 1906569e2a5fc..2f7ec9249e340 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h @@ -59,6 +59,7 @@ char *internal_strdup(const char *s); uptr internal_strlen(const char *s); uptr internal_strlcat(char *dst, const char *src, uptr maxlen); char *internal_strncat(char *dst, const char *src, uptr n); +char* internal_strcat(char* dst, const char* src); int internal_strncmp(const char *s1, const char *s2, uptr n); uptr internal_strlcpy(char *dst, const char *src, uptr maxlen); char *internal_strncpy(char *dst, const char *src, uptr n); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 741f0924614a9..f65085ffcc564 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -646,7 +646,7 @@ bool DirExists(const char *path) { } # if !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN -tid_t GetTid() { +ThreadID GetTid() { # if SANITIZER_FREEBSD long Tid; thr_self(&Tid); @@ -661,7 +661,7 @@ tid_t GetTid() { } # if !SANITIZER_EMSCRIPTEN -int TgKill(pid_t pid, tid_t tid, int sig) { +int TgKill(pid_t pid, ThreadID tid, int sig) { # if SANITIZER_LINUX return internal_syscall(SYSCALL(tgkill), pid, tid, sig); # elif SANITIZER_FREEBSD @@ -1108,7 +1108,7 @@ ThreadLister::ThreadLister(pid_t pid) : buffer_(4096) { } ThreadLister::Result ThreadLister::ListThreads( - InternalMmapVector *threads) { + InternalMmapVector *threads) { int descriptor = internal_open(task_path_.data(), O_RDONLY | O_DIRECTORY); if (internal_iserror(descriptor)) { Report("Can't open %s for reading.\n", task_path_.data()); @@ -1163,7 +1163,7 @@ ThreadLister::Result ThreadLister::ListThreads( } } -const char *ThreadLister::LoadStatus(tid_t tid) { +const char *ThreadLister::LoadStatus(ThreadID tid) { status_path_.clear(); status_path_.AppendF("%s/%llu/status", task_path_.data(), tid); auto cleanup = at_scope_exit([&] { @@ -1176,7 +1176,7 @@ const char *ThreadLister::LoadStatus(tid_t tid) { return buffer_.data(); } -bool ThreadLister::IsAlive(tid_t tid) { +bool ThreadLister::IsAlive(ThreadID tid) { // /proc/%d/task/%d/status uses same call to detect alive threads as // proc_task_readdir. See task_state implementation in Linux. static const char kPrefix[] = "\nPPid:"; @@ -1310,7 +1310,7 @@ extern "C" void _emscripten_get_progname(char *buf, int buf_len); uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { # if SANITIZER_HAIKU - int32_t cookie = 0; + int32 cookie = 0; image_info info; const char *argv0 = ""; while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h index 27a3ef3ac7113..482110bcf1b80 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -108,11 +108,11 @@ class ThreadLister { Incomplete, Ok, }; - Result ListThreads(InternalMmapVector *threads); - const char *LoadStatus(tid_t tid); + Result ListThreads(InternalMmapVector *threads); + const char *LoadStatus(ThreadID tid); private: - bool IsAlive(tid_t tid); + bool IsAlive(ThreadID tid); InternalScopedString task_path_; InternalScopedString status_path_; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp index bb71af5ad8b6a..940175791f376 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -22,6 +22,11 @@ # endif # include +// Start searching for available memory region past PAGEZERO, which is +// 4KB on 32-bit and 4GB on 64-bit. +# define GAP_SEARCH_START_ADDRESS \ + ((SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000) + # include "sanitizer_common.h" # include "sanitizer_file.h" # include "sanitizer_flags.h" @@ -58,9 +63,11 @@ extern char ***_NSGetArgv(void); # include // for dladdr() # include # include +# include # include # include # include +# include # include # include # include @@ -96,8 +103,16 @@ extern "C" { natural_t *nesting_depth, vm_region_recurse_info_t info, mach_msg_type_number_t *infoCnt); + + extern const void* _dyld_get_shared_cache_range(size_t* length); } +# if !SANITIZER_GO +// Weak symbol no-op when TSan is not linked +SANITIZER_WEAK_ATTRIBUTE extern void __tsan_set_in_internal_write_call( + bool value) {} +# endif + namespace __sanitizer { #include "sanitizer_syscall_generic.inc" @@ -168,7 +183,15 @@ uptr internal_read(fd_t fd, void *buf, uptr count) { } uptr internal_write(fd_t fd, const void *buf, uptr count) { +# if SANITIZER_GO return write(fd, buf, count); +# else + // We need to disable interceptors when writing in TSan + __tsan_set_in_internal_write_call(true); + uptr res = write(fd, buf, count); + __tsan_set_in_internal_write_call(false); + return res; +# endif } uptr internal_stat(const char *path, void *buf) { @@ -258,53 +281,43 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, (size_t)newlen); } -static fd_t internal_spawn_impl(const char *argv[], const char *envp[], - pid_t *pid) { - fd_t primary_fd = kInvalidFd; - fd_t secondary_fd = kInvalidFd; +bool internal_spawn(const char* argv[], const char* envp[], pid_t* pid, + fd_t fd_stdin, fd_t fd_stdout) { + // NOTE: Caller ensures that fd_stdin and fd_stdout are not 0, 1, or 2, since + // this can break communication. + // + // NOTE: Caller is responsible for closing fd_stdin after the process has + // died. + int res; auto fd_closer = at_scope_exit([&] { - internal_close(primary_fd); - internal_close(secondary_fd); + // NOTE: We intentionally do not close fd_stdin since this can + // cause us to receive a fatal SIGPIPE if the process dies. + internal_close(fd_stdout); }); - // We need a new pseudoterminal to avoid buffering problems. The 'atos' tool - // in particular detects when it's talking to a pipe and forgets to flush the - // output stream after sending a response. - primary_fd = posix_openpt(O_RDWR); - if (primary_fd == kInvalidFd) - return kInvalidFd; - - int res = grantpt(primary_fd) || unlockpt(primary_fd); - if (res != 0) return kInvalidFd; - - // Use TIOCPTYGNAME instead of ptsname() to avoid threading problems. - char secondary_pty_name[128]; - res = ioctl(primary_fd, TIOCPTYGNAME, secondary_pty_name); - if (res == -1) return kInvalidFd; - - secondary_fd = internal_open(secondary_pty_name, O_RDWR); - if (secondary_fd == kInvalidFd) - return kInvalidFd; - // File descriptor actions posix_spawn_file_actions_t acts; res = posix_spawn_file_actions_init(&acts); - if (res != 0) return kInvalidFd; + if (res != 0) + return false; auto acts_cleanup = at_scope_exit([&] { posix_spawn_file_actions_destroy(&acts); }); - res = posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDIN_FILENO) || - posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDOUT_FILENO) || - posix_spawn_file_actions_addclose(&acts, secondary_fd); - if (res != 0) return kInvalidFd; + res = posix_spawn_file_actions_adddup2(&acts, fd_stdin, STDIN_FILENO) || + posix_spawn_file_actions_adddup2(&acts, fd_stdout, STDOUT_FILENO) || + posix_spawn_file_actions_addclose(&acts, fd_stdin) || + posix_spawn_file_actions_addclose(&acts, fd_stdout); + if (res != 0) + return false; // Spawn attributes posix_spawnattr_t attrs; res = posix_spawnattr_init(&attrs); - if (res != 0) return kInvalidFd; + if (res != 0) + return false; auto attrs_cleanup = at_scope_exit([&] { posix_spawnattr_destroy(&attrs); @@ -313,50 +326,17 @@ static fd_t internal_spawn_impl(const char *argv[], const char *envp[], // In the spawned process, close all file descriptors that are not explicitly // described by the file actions object. This is Darwin-specific extension. res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT); - if (res != 0) return kInvalidFd; + if (res != 0) + return false; // posix_spawn char **argv_casted = const_cast(argv); char **envp_casted = const_cast(envp); res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted); - if (res != 0) return kInvalidFd; - - // Disable echo in the new terminal, disable CR. - struct termios termflags; - tcgetattr(primary_fd, &termflags); - termflags.c_oflag &= ~ONLCR; - termflags.c_lflag &= ~ECHO; - tcsetattr(primary_fd, TCSANOW, &termflags); - - // On success, do not close primary_fd on scope exit. - fd_t fd = primary_fd; - primary_fd = kInvalidFd; - - return fd; -} - -fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) { - // The client program may close its stdin and/or stdout and/or stderr thus - // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this - // case the communication is broken if either the parent or the child tries to - // close or duplicate these descriptors. We temporarily reserve these - // descriptors here to prevent this. - fd_t low_fds[3]; - size_t count = 0; - - for (; count < 3; count++) { - low_fds[count] = posix_openpt(O_RDWR); - if (low_fds[count] >= STDERR_FILENO) - break; - } - - fd_t fd = internal_spawn_impl(argv, envp, pid); - - for (; count > 0; count--) { - internal_close(low_fds[count]); - } + if (res != 0) + return false; - return fd; + return true; } uptr internal_rename(const char *oldpath, const char *newpath) { @@ -394,8 +374,8 @@ bool DirExists(const char *path) { return S_ISDIR(st.st_mode); } -tid_t GetTid() { - tid_t tid; +ThreadID GetTid() { + ThreadID tid; pthread_threadid_np(nullptr, &tid); return tid; } @@ -769,11 +749,17 @@ void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); } static Mutex syslog_lock; # endif +# if SANITIZER_DRIVERKIT +# define SANITIZER_OS_LOG os_log +# else +# define SANITIZER_OS_LOG os_log_error +# endif + void WriteOneLineToSyslog(const char *s) { #if !SANITIZER_GO syslog_lock.CheckLocked(); if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) { - os_log_error(OS_LOG_DEFAULT, "%{public}s", s); + SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s", s); } else { #pragma clang diagnostic push // as_log is deprecated. @@ -837,22 +823,22 @@ void LogMessageOnPrintf(const char *str) { void LogFullErrorReport(const char *buffer) { # if !SANITIZER_GO - // Log with os_log_error. This will make it into the crash log. + // When logging with os_log_error this will make it into the crash log. if (internal_strncmp(SanitizerToolName, "AddressSanitizer", sizeof("AddressSanitizer") - 1) == 0) - os_log_error(OS_LOG_DEFAULT, "Address Sanitizer reported a failure."); + SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Address Sanitizer reported a failure."); else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer", sizeof("UndefinedBehaviorSanitizer") - 1) == 0) - os_log_error(OS_LOG_DEFAULT, - "Undefined Behavior Sanitizer reported a failure."); + SANITIZER_OS_LOG(OS_LOG_DEFAULT, + "Undefined Behavior Sanitizer reported a failure."); else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer", sizeof("ThreadSanitizer") - 1) == 0) - os_log_error(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure."); + SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure."); else - os_log_error(OS_LOG_DEFAULT, "Sanitizer tool reported a failure."); + SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Sanitizer tool reported a failure."); if (common_flags()->log_to_syslog) - os_log_error(OS_LOG_DEFAULT, "Consult syslog for more information."); + SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Consult syslog for more information."); // Log to syslog. // The logging on OS X may call pthread_create so we need the threading @@ -933,7 +919,17 @@ static void DisableMmapExcGuardExceptions() { RTLD_DEFAULT, "task_set_exc_guard_behavior"); if (set_behavior == nullptr) return; const task_exc_guard_behavior_t task_exc_guard_none = 0; - set_behavior(mach_task_self(), task_exc_guard_none); + kern_return_t res = set_behavior(mach_task_self(), task_exc_guard_none); + if (res != KERN_SUCCESS) { + Report( + "WARN: task_set_exc_guard_behavior returned %d (%s), " + "mmap may fail unexpectedly.\n", + res, mach_error_string(res)); + if (res == KERN_DENIED) + Report( + "HINT: Check that task_set_exc_guard_behavior is allowed by " + "sandbox.\n"); + } } static void VerifyInterceptorsWorking(); @@ -1100,6 +1096,67 @@ static void StripEnv() { } #endif // SANITIZER_GO +// Prints out a consolidated memory map: contiguous regions +// are merged together. +static void PrintVmmap() { + const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1; + mach_vm_address_t address = GAP_SEARCH_START_ADDRESS; + kern_return_t kr = KERN_SUCCESS; + + Report("Memory map:\n"); + mach_vm_address_t last = 0; + mach_vm_address_t lastsz = 0; + + while (1) { + mach_vm_size_t vmsize = 0; + natural_t depth = 0; + vm_region_submap_short_info_data_64_t vminfo; + mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; + kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, + (vm_region_info_t)&vminfo, &count); + + if (kr == KERN_DENIED) { + Report( + "ERROR: mach_vm_region_recurse got KERN_DENIED when printing memory " + "map.\n"); + Report( + "HINT: Check whether mach_vm_region_recurse is allowed by " + "sandbox.\n"); + } + + if (kr == KERN_SUCCESS && address < max_vm_address) { + if (last + lastsz == address) { + // This region is contiguous with the last; merge together. + lastsz += vmsize; + } else { + if (lastsz) + Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last, + (void*)(last + lastsz), lastsz); + + last = address; + lastsz = vmsize; + } + address += vmsize; + } else { + // We've reached the end of the memory map. Print the last remaining + // region, if there is one. + if (lastsz) + Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last, + (void*)(last + lastsz), lastsz); + + break; + } + } +} + +static void ReportShadowAllocFail(uptr shadow_size_bytes, uptr alignment) { + Report( + "FATAL: Failed to allocate shadow memory. Tried to allocate %p bytes " + "(alignment=%p).\n", + (void*)shadow_size_bytes, (void*)alignment); + PrintVmmap(); +} + char **GetArgv() { return *_NSGetArgv(); } @@ -1207,10 +1264,11 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, if (new_max_vm < max_occupied_addr) { Report("Unable to find a memory range for dynamic shadow.\n"); Report( - "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, " - "new_max_vm = %p\n", - (void *)space_size, (void *)largest_gap_found, - (void *)max_occupied_addr, (void *)new_max_vm); + "\tspace_size = %p\n\tlargest_gap_found = %p\n\tmax_occupied_addr " + "= %p\n\tnew_max_vm = %p\n", + (void*)space_size, (void*)largest_gap_found, (void*)max_occupied_addr, + (void*)new_max_vm); + ReportShadowAllocFail(shadow_size_bytes, alignment); CHECK(0 && "cannot place shadow"); } RestrictMemoryToMaxAddress(new_max_vm); @@ -1221,6 +1279,7 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, nullptr, nullptr); if (shadow_start == 0) { Report("Unable to find a memory range after restricting VM.\n"); + ReportShadowAllocFail(shadow_size_bytes, alignment); CHECK(0 && "cannot place shadow after restricting vm"); } } @@ -1229,6 +1288,25 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, return shadow_start; } +// Returns a list of ranges which must be covered by shadow memory, +// and cannot overlap with any fixed mappings made by a sanitizer. +// This can ensure that the sanitizer runtime does not map over +// platform-reserved regions. +void GetAppReservedRanges(InternalMmapVector& ranges) { + ranges.clear(); + +# if SANITIZER_OSX + // On macOS, the first 512GB are platform-reserved (some of which + // may also be available to applications). + ranges.push_back({0x1000UL, 0x8000000000UL}); +# endif + + VReport(2, "App ranges:\n"); + for (auto& [range_start, range_end] : ranges) { + VReport(2, " [%p, %p]\n", range_start, range_end); + } +} + uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, uptr num_aliases, uptr ring_buffer_size) { CHECK(false && "HWASan aliasing is unimplemented on Mac"); @@ -1236,40 +1314,61 @@ uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, } uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, - uptr *largest_gap_found, - uptr *max_occupied_addr) { - typedef vm_region_submap_short_info_data_64_t RegionInfo; - enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; - // Start searching for available memory region past PAGEZERO, which is - // 4KB on 32-bit and 4GB on 64-bit. - mach_vm_address_t start_address = - (SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000; - + uptr* largest_gap_found, + uptr* max_occupied_addr) { const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1; - mach_vm_address_t address = start_address; - mach_vm_address_t free_begin = start_address; + mach_vm_address_t address = GAP_SEARCH_START_ADDRESS; + mach_vm_address_t free_begin = GAP_SEARCH_START_ADDRESS; + + // Restrict the search to be after any reserved ranges + InternalMmapVector app_ranges; + GetAppReservedRanges(app_ranges); + + for (auto& [range_start, range_end] : app_ranges) { + address = Max(address, (mach_vm_address_t)range_end); + free_begin = Max(free_begin, (mach_vm_address_t)range_end); + } + kern_return_t kr = KERN_SUCCESS; if (largest_gap_found) *largest_gap_found = 0; if (max_occupied_addr) *max_occupied_addr = 0; while (kr == KERN_SUCCESS) { mach_vm_size_t vmsize = 0; natural_t depth = 0; - RegionInfo vminfo; - mach_msg_type_number_t count = kRegionInfoSize; + vm_region_submap_short_info_data_64_t vminfo; + mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, (vm_region_info_t)&vminfo, &count); - // There are cases where going beyond the processes' max vm does - // not return KERN_INVALID_ADDRESS so we check for going beyond that - // max address as well. - if (kr == KERN_INVALID_ADDRESS || address > max_vm_address) { + if (kr == KERN_SUCCESS) { + // There are cases where going beyond the processes' max vm does + // not return KERN_INVALID_ADDRESS so we check for going beyond that + // max address as well. + if (address > max_vm_address) { + address = max_vm_address; + kr = -1; // break after this iteration. + } + + if (max_occupied_addr) + *max_occupied_addr = address + vmsize; + } else if (kr == KERN_INVALID_ADDRESS) { // No more regions beyond "address", consider the gap at the end of VM. address = max_vm_address; - vmsize = 0; - kr = -1; // break after this iteration. + + // We will break after this iteration anyway since kr != KERN_SUCCESS + } else if (kr == KERN_DENIED) { + Report("ERROR: Unable to find a memory range for dynamic shadow.\n"); + Report("HINT: Ensure mach_vm_region_recurse is allowed under sandbox.\n"); + Die(); } else { - if (max_occupied_addr) *max_occupied_addr = address + vmsize; + Report( + "WARNING: mach_vm_region_recurse returned unexpected code %d (%s)\n", + kr, mach_error_string(kr)); + DCHECK(false && "mach_vm_region_recurse returned unexpected code"); + break; // address is not valid unless KERN_SUCCESS, therefore we must not + // use it. } + if (free_begin != address) { // We found a free region [free_begin..address-1]. uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment); @@ -1292,6 +1391,58 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, return 0; } +// This function (when used during initialization when there is +// only a single thread), can be used to verify that a range +// of memory hasn't already been mapped, and won't be mapped +// later in the shared cache. +// +// If the syscall mach_vm_region_recurse fails (due to sandbox), +// we assume that the memory is not mapped so that execution can continue. +// +// NOTE: range_end is inclusive +// +// WARNING: This function must NOT allocate memory, since it is +// used in InitializeShadowMemory between where we search for +// space for shadow and where we actually allocate it. +bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { + mach_vm_size_t vmsize = 0; + natural_t depth = 0; + vm_region_submap_short_info_data_64_t vminfo; + mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; + mach_vm_address_t address = range_start; + + // First, check if the range is already mapped. + kern_return_t kr = + mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, + (vm_region_info_t)&vminfo, &count); + + if (kr == KERN_DENIED) { + Report( + "WARN: mach_vm_region_recurse returned KERN_DENIED when checking " + "whether an address is mapped.\n"); + Report("HINT: Is mach_vm_region_recurse allowed by sandbox?\n"); + } + + if (kr == KERN_SUCCESS && !IntervalsAreSeparate(address, address + vmsize - 1, + range_start, range_end)) { + // Overlaps with already-mapped memory + return false; + } + + size_t cacheLength; + uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength); + + if (cacheStart && + !IntervalsAreSeparate(cacheStart, cacheStart + cacheLength - 1, + range_start, range_end)) { + // Overlaps with shared cache region + return false; + } + + // We believe this address is available. + return true; +} + // FIXME implement on this platform. void GetMemoryProfile(fill_profile_f cb, uptr *stats) {} diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h index b0e4ac7f40745..7f9a2b77e7d50 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h @@ -58,8 +58,13 @@ struct DarwinKernelVersion : VersionBase { DarwinKernelVersion(u16 major, u16 minor) : VersionBase(major, minor) {} }; +struct ReservedRange { + uptr beg, end; +}; + MacosVersion GetMacosAlignedVersion(); DarwinKernelVersion GetDarwinKernelVersion(); +void GetAppReservedRanges(InternalMmapVector& ranges); char **GetEnviron(); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp index 5e601bdcde1e5..737e336dfbe87 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp @@ -229,12 +229,12 @@ uptr internal_execve(const char *filename, char *const argv[], return _sys_execve(filename, argv, envp); } -tid_t GetTid() { +ThreadID GetTid() { DEFINE__REAL(int, _lwp_self); return _REAL(_lwp_self); } -int TgKill(pid_t pid, tid_t tid, int sig) { +int TgKill(pid_t pid, ThreadID tid, int sig) { DEFINE__REAL(int, _lwp_kill, int a, int b); (void)pid; return _REAL(_lwp_kill, tid, sig); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index 906ea0810e087..144d8b9949c09 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h @@ -325,7 +325,11 @@ #endif // The first address that can be returned by mmap. -#define SANITIZER_MMAP_BEGIN 0 +#if SANITIZER_AIX && SANITIZER_WORDSIZE == 64 +# define SANITIZER_MMAP_BEGIN 0x0a00'0000'0000'0000ULL +#else +# define SANITIZER_MMAP_BEGIN 0 +#endif // The range of addresses which can be returned my mmap. // FIXME: this value should be different on different platforms. Larger values @@ -505,4 +509,11 @@ # endif #endif +#if SANITIZER_APPLE && SANITIZER_WORDSIZE == 64 +// MTE uses the lower half of the top byte. +# define STRIP_MTE_TAG(addr) ((addr) & ~((uptr)0x0f << 56)) +#else +# define STRIP_MTE_TAG(addr) (addr) +#endif + #endif // SANITIZER_PLATFORM_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 489a79158bc59..5153a55986086 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -179,7 +179,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA) -#define SANITIZER_INTERCEPT_STRCMP (SI_NOT_FUCHSIA && SI_NOT_AIX) +#define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRCASESTR (SI_POSIX && SI_NOT_AIX) #define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA @@ -191,8 +191,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX #define SANITIZER_INTERCEPT_MEMSET 1 -#define SANITIZER_INTERCEPT_MEMMOVE SI_NOT_AIX -#define SANITIZER_INTERCEPT_MEMCPY SI_NOT_AIX +#define SANITIZER_INTERCEPT_MEMMOVE 1 +#define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_BCMP \ SANITIZER_INTERCEPT_MEMCMP && \ @@ -563,7 +563,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSLEN 1 -#define SANITIZER_INTERCEPT_WCSCAT SI_POSIX +#define SANITIZER_INTERCEPT_WCSNLEN 1 +#define SANITIZER_INTERCEPT_WCSCAT (SI_POSIX || SI_WINDOWS) #define SANITIZER_INTERCEPT_WCSDUP SI_POSIX #define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp index 8824d136e2fdb..0fa1cbb7099a7 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -152,16 +152,15 @@ typedef struct user_fpregs elf_fpregset_t; #if defined(__mips64) # include #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +# include +# include +# include +# include +# include +# include +# include +# include +# include #endif // SANITIZER_ANDROID #include @@ -536,8 +535,6 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_kbsentry_sz = sizeof(struct kbsentry); unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo); unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct); - unsigned struct_scc_modem_sz = sizeof(struct scc_modem); - unsigned struct_scc_stat_sz = sizeof(struct scc_stat); unsigned struct_serial_multiport_struct_sz = sizeof(struct serial_multiport_struct); unsigned struct_serial_struct_sz = sizeof(struct serial_struct); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 4397a30319664..377fdca7545fa 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -30,6 +30,8 @@ # define SANITIZER_HAS_STAT64 0 # define SANITIZER_HAS_STATFS64 0 # endif +# elif SANITIZER_HAIKU +# include # elif SANITIZER_EMSCRIPTEN # define SANITIZER_HAS_STAT64 0 # define SANITIZER_HAS_STATFS64 0 @@ -644,7 +646,7 @@ typedef unsigned long __sanitizer_sigset_t; # elif SANITIZER_APPLE typedef unsigned __sanitizer_sigset_t; # elif SANITIZER_HAIKU -typedef unsigned long long __sanitizer_sigset_t; +typedef uint64_t __sanitizer_sigset_t; # elif SANITIZER_LINUX struct __sanitizer_sigset_t { // The size is determined by looking at sizeof of real sigset_t on linux. diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp index 725008e5783cf..0aa70bf4a3a0d 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp @@ -243,17 +243,9 @@ void DumpProcessMap() { Report("Cannot dump memory map on emscripten"); } #else -static inline bool IntervalsAreSeparate(uptr start1, uptr end1, - uptr start2, uptr end2) { - CHECK(start1 <= end1); - CHECK(start2 <= end2); - return (end1 < start2) || (end2 < start1); -} - +#if !SANITIZER_APPLE // FIXME: this is thread-unsafe, but should not cause problems most of the time. -// When the shadow is mapped only a single thread usually exists (plus maybe -// several worker threads on Mac, which aren't expected to map big chunks of -// memory). +// When the shadow is mapped only a single thread usually exists bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { MemoryMappingLayout proc_maps(/*cache_enabled*/true); if (proc_maps.Error()) @@ -269,7 +261,6 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { return true; } -#if !SANITIZER_APPLE void DumpProcessMap() { MemoryMappingLayout proc_maps(/*cache_enabled*/true); const sptr kBufSize = 4095; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h index b5491c540dc08..dc9c3b8822d30 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h @@ -67,7 +67,8 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data); uptr internal_waitpid(int pid, int *status, int options); int internal_fork(); -fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid); +bool internal_spawn(const char* argv[], const char* envp[], pid_t* pid, + fd_t fd_stdin, fd_t fd_stdout); int internal_sysctl(const int *name, unsigned int namelen, void *oldp, uptr *oldlenp, const void *newp, uptr newlen); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index 39ec00f2c7616..fd1b69edea136 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -47,6 +47,8 @@ typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); namespace __sanitizer { +[[maybe_unused]] static atomic_uint8_t signal_handler_is_from_sanitizer[64]; + u32 GetUid() { return getuid(); } @@ -212,6 +214,20 @@ void UnsetAlternateSignalStack() { UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); } +bool IsSignalHandlerFromSanitizer(int signum) { + return atomic_load(&signal_handler_is_from_sanitizer[signum], + memory_order_relaxed); +} + +bool SetSignalHandlerFromSanitizer(int signum, bool new_state) { + if (signum < 0 || static_cast(signum) >= + ARRAY_SIZE(signal_handler_is_from_sanitizer)) + return false; + + return atomic_exchange(&signal_handler_is_from_sanitizer[signum], new_state, + memory_order_relaxed); +} + static void MaybeInstallSigaction(int signum, SignalHandlerType handler) { if (GetHandleSignalMode(signum) == kHandleSignalNo) return; @@ -225,6 +241,9 @@ static void MaybeInstallSigaction(int signum, if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); VReport(1, "Installed the sigaction for signal %d\n", signum); + + if (common_flags()->cloak_sanitizer_signal_handlers) + SetSignalHandlerFromSanitizer(signum, true); } void InstallDeadlySignalHandlers(SignalHandlerType handler) { diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp index a9533d6fc04ca..93d3929033a86 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp @@ -20,18 +20,21 @@ #include // These are not available in older macOS SDKs. -#ifndef CPU_SUBTYPE_X86_64_H -#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */ -#endif -#ifndef CPU_SUBTYPE_ARM_V7S -#define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */ -#endif -#ifndef CPU_SUBTYPE_ARM_V7K -#define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12) -#endif -#ifndef CPU_TYPE_ARM64 -#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) -#endif +# ifndef CPU_SUBTYPE_X86_64_H +# define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */ +# endif +# ifndef CPU_SUBTYPE_ARM_V7S +# define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */ +# endif +# ifndef CPU_SUBTYPE_ARM_V7K +# define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12) +# endif +# ifndef CPU_TYPE_ARM64 +# define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +# endif +# ifndef CPU_SUBTYPE_ARM64E +# define CPU_SUBTYPE_ARM64E ((cpu_subtype_t)2) +# endif namespace __sanitizer { @@ -42,7 +45,6 @@ struct MemoryMappedSegmentData { const char *current_load_cmd_addr; u32 lc_type; uptr base_virt_addr; - uptr addr_mask; }; template @@ -51,12 +53,62 @@ static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data, const Section *sc = (const Section *)data->current_load_cmd_addr; data->current_load_cmd_addr += sizeof(Section); - uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr; + uptr sec_start = sc->addr + data->base_virt_addr; uptr sec_end = sec_start + sc->size; module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable, sc->sectname); } +static bool VerifyMemoryMapping(MemoryMappingLayout* mapping) { + InternalMmapVector modules; + modules.reserve(128); // matches DumpProcessMap + mapping->DumpListOfModules(&modules); + + InternalMmapVector segments; + for (uptr i = 0; i < modules.size(); ++i) { + for (auto& range : modules[i].ranges()) { + if (range.beg == range.end) + continue; + segments.push_back(range); + } + } + + // Verify that none of the segments overlap: + // 1. Sort the segments by the start address + // 2. Check that every segment starts after the previous one ends. + Sort(segments.data(), segments.size(), + [](LoadedModule::AddressRange& a, LoadedModule::AddressRange& b) { + return a.beg < b.beg; + }); + + // To avoid spam, we only print the report message once-per-process. + static bool invalid_module_map_reported = false; + bool well_formed = true; + + for (size_t i = 1; i < segments.size(); i++) { + uptr cur_start = segments[i].beg; + uptr prev_end = segments[i - 1].end; + if (cur_start < prev_end) { + well_formed = false; + VReport(2, "Overlapping mappings: %s start = %p, %s end = %p\n", + segments[i].name, (void*)cur_start, segments[i - 1].name, + (void*)prev_end); + if (!invalid_module_map_reported) { + Report( + "WARN: Invalid dyld module map detected. This is most likely a bug " + "in the sanitizer.\n"); + Report("WARN: Backtraces may be unreliable.\n"); + invalid_module_map_reported = true; + } + } + } + + for (auto& m : modules) m.clear(); + + mapping->Reset(); + return well_formed; +} + void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { // Don't iterate over sections when the caller hasn't set up the // data pointer, when there are no sections, or when the segment @@ -82,6 +134,7 @@ void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { Reset(); + VerifyMemoryMapping(this); } MemoryMappingLayout::~MemoryMappingLayout() { @@ -123,7 +176,7 @@ void MemoryMappingLayout::Reset() { // The dyld load address should be unchanged throughout process execution, // and it is expensive to compute once many libraries have been loaded, // so cache it here and do not reset. -static mach_header *dyld_hdr = 0; +static const mach_header* dyld_hdr = 0; static const char kDyldPath[] = "/usr/lib/dyld"; static const int kDyldImageIdx = -1; @@ -187,17 +240,22 @@ typedef struct dyld_shared_cache_dylib_text_info extern bool _dyld_get_shared_cache_uuid(uuid_t uuid); extern const void *_dyld_get_shared_cache_range(size_t *length); +extern intptr_t _dyld_get_image_slide(const struct mach_header* mh); extern int dyld_shared_cache_iterate_text( const uuid_t cacheUuid, void (^callback)(const dyld_shared_cache_dylib_text_info *info)); +SANITIZER_WEAK_IMPORT const struct mach_header* _dyld_get_dyld_header(void); } // extern "C" -static mach_header *GetDyldImageHeaderViaSharedCache() { +static const mach_header* GetDyldImageHeaderViaSharedCache() { uuid_t uuid; bool hasCache = _dyld_get_shared_cache_uuid(uuid); if (!hasCache) return nullptr; + if (&_dyld_get_dyld_header != nullptr) + return _dyld_get_dyld_header(); + size_t cacheLength; __block uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength); CHECK(cacheStart && cacheLength); @@ -255,23 +313,21 @@ static bool NextSegmentLoad(MemoryMappedSegment *segment, layout_data->current_load_cmd_count--; if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; - uptr base_virt_addr, addr_mask; - if (layout_data->current_image == kDyldImageIdx) { - base_virt_addr = (uptr)get_dyld_hdr(); - // vmaddr is masked with 0xfffff because on macOS versions < 10.12, - // it contains an absolute address rather than an offset for dyld. - // To make matters even more complicated, this absolute address - // isn't actually the absolute segment address, but the offset portion - // of the address is accurate when combined with the dyld base address, - // and the mask will give just this offset. - addr_mask = 0xfffff; - } else { + if (internal_strcmp(sc->segname, "__LINKEDIT") == 0) { + // The LINKEDIT sections are for internal linker use, and may alias + // with the LINKEDIT section for other modules. (If we included them, + // our memory map would contain overlappping sections.) + return false; + } + + uptr base_virt_addr; + if (layout_data->current_image == kDyldImageIdx) + base_virt_addr = (uptr)_dyld_get_image_slide(get_dyld_hdr()); + else base_virt_addr = (uptr)_dyld_get_image_vmaddr_slide(layout_data->current_image); - addr_mask = ~0; - } - segment->start = (sc->vmaddr & addr_mask) + base_virt_addr; + segment->start = sc->vmaddr + base_virt_addr; segment->end = segment->start + sc->vmsize; // Most callers don't need section information, so only fill this struct // when required. @@ -281,9 +337,9 @@ static bool NextSegmentLoad(MemoryMappedSegment *segment, (const char *)lc + sizeof(SegmentCommand); seg_data->lc_type = kLCSegment; seg_data->base_virt_addr = base_virt_addr; - seg_data->addr_mask = addr_mask; internal_strncpy(seg_data->name, sc->segname, ARRAY_SIZE(seg_data->name)); + seg_data->name[ARRAY_SIZE(seg_data->name) - 1] = 0; } // Return the initial protection. @@ -297,6 +353,7 @@ static bool NextSegmentLoad(MemoryMappedSegment *segment, ? kDyldPath : _dyld_get_image_name(layout_data->current_image); internal_strncpy(segment->filename, src, segment->filename_size); + segment->filename[segment->filename_size - 1] = 0; } segment->arch = layout_data->current_arch; internal_memcpy(segment->uuid, layout_data->current_uuid, kModuleUUIDSize); @@ -311,18 +368,26 @@ ModuleArch ModuleArchFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype) { case CPU_TYPE_I386: return kModuleArchI386; case CPU_TYPE_X86_64: - if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) return kModuleArchX86_64; - if (cpusubtype == CPU_SUBTYPE_X86_64_H) return kModuleArchX86_64H; + if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) + return kModuleArchX86_64; + if (cpusubtype == CPU_SUBTYPE_X86_64_H) + return kModuleArchX86_64H; CHECK(0 && "Invalid subtype of x86_64"); return kModuleArchUnknown; case CPU_TYPE_ARM: - if (cpusubtype == CPU_SUBTYPE_ARM_V6) return kModuleArchARMV6; - if (cpusubtype == CPU_SUBTYPE_ARM_V7) return kModuleArchARMV7; - if (cpusubtype == CPU_SUBTYPE_ARM_V7S) return kModuleArchARMV7S; - if (cpusubtype == CPU_SUBTYPE_ARM_V7K) return kModuleArchARMV7K; + if (cpusubtype == CPU_SUBTYPE_ARM_V6) + return kModuleArchARMV6; + if (cpusubtype == CPU_SUBTYPE_ARM_V7) + return kModuleArchARMV7; + if (cpusubtype == CPU_SUBTYPE_ARM_V7S) + return kModuleArchARMV7S; + if (cpusubtype == CPU_SUBTYPE_ARM_V7K) + return kModuleArchARMV7K; CHECK(0 && "Invalid subtype of ARM"); return kModuleArchUnknown; case CPU_TYPE_ARM64: + if (cpusubtype == CPU_SUBTYPE_ARM64E) + return kModuleArchARM64E; return kModuleArchARM64; default: CHECK(0 && "Invalid CPU type"); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h index 9000a3e5e45dd..9d6e471bd4f87 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h @@ -16,7 +16,8 @@ // The asm hack only works with GCC and Clang. // XXX Emscripten This does not work in Wasm. -# if !defined(_WIN32) && !defined(_AIX) && !defined(__wasm__) +# if !defined(_WIN32) && !defined(_AIX) && !defined(__APPLE__) && \ + !defined(__wasm__) asm(R"( .set memcpy, __sanitizer_internal_memcpy diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index 94e4e2954a3b9..8511e4d55fa9e 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -45,6 +45,8 @@ using namespace __sanitizer; INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { SIGNAL_INTERCEPTOR_ENTER(); if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; + + // TODO: support cloak_sanitizer_signal_handlers SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler); } #define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal) @@ -56,19 +58,55 @@ INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { INTERCEPTOR(uptr, signal, int signum, uptr handler) { SIGNAL_INTERCEPTOR_ENTER(); if (GetHandleSignalMode(signum) == kHandleSignalExclusive) + // The user can neither view nor change the signal handler, regardless of + // the cloak_sanitizer_signal_handlers setting. This differs from + // sigaction(). return (uptr) nullptr; - SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); + + uptr ret = +[](auto signal, int signum, uptr handler) { + SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); + }(signal, signum, handler); + + if (ret != sig_err && SetSignalHandlerFromSanitizer(signum, false)) + // If the user sets a signal handler, it becomes uncloaked, even if they + // reuse a sanitizer's signal handler. + ret = sig_dfl; + + return ret; } #define INIT_SIGNAL COMMON_INTERCEPT_FUNCTION(signal) INTERCEPTOR(int, sigaction_symname, int signum, const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { SIGNAL_INTERCEPTOR_ENTER(); + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) { if (!oldact) return 0; act = nullptr; + // If cloak_sanitizer_signal_handlers=true, the user can neither view nor + // change the signal handle. + // If false, the user can view but not change the signal handler. This + // differs from signal(). } - SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); + + int ret = +[](int signum, const __sanitizer_sigaction* act, + __sanitizer_sigaction* oldact) { + SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); + }(signum, act, oldact); + + if (act) { + if (ret == 0 && SetSignalHandlerFromSanitizer(signum, false)) { + // If the user sets a signal handler, it becomes uncloaked, even if they + // reuse a sanitizer's signal handler. + + if (oldact) + oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); + } + } else if (ret == 0 && oldact && IsSignalHandlerFromSanitizer(signum)) { + oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); + } + + return ret; } #define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname) diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h index 7891c1081fe71..b4ed23abb964f 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h @@ -38,7 +38,7 @@ class SuspendedThreadsList { } virtual uptr ThreadCount() const { UNIMPLEMENTED(); } - virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); } + virtual ThreadID GetThreadID(uptr index) const { UNIMPLEMENTED(); } protected: ~SuspendedThreadsList() {} diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp index 24929b8c4bd7c..2bf547f4a7216 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp @@ -94,17 +94,17 @@ class SuspendedThreadsListLinux final : public SuspendedThreadsList { public: SuspendedThreadsListLinux() { thread_ids_.reserve(1024); } - tid_t GetThreadID(uptr index) const override; + ThreadID GetThreadID(uptr index) const override; uptr ThreadCount() const override; - bool ContainsTid(tid_t thread_id) const; - void Append(tid_t tid); + bool ContainsTid(ThreadID thread_id) const; + void Append(ThreadID tid); PtraceRegistersStatus GetRegistersAndSP(uptr index, InternalMmapVector *buffer, uptr *sp) const override; private: - InternalMmapVector thread_ids_; + InternalMmapVector thread_ids_; }; // Structure for passing arguments into the tracer thread. @@ -137,10 +137,10 @@ class ThreadSuspender { private: SuspendedThreadsListLinux suspended_threads_list_; pid_t pid_; - bool SuspendThread(tid_t thread_id); + bool SuspendThread(ThreadID thread_id); }; -bool ThreadSuspender::SuspendThread(tid_t tid) { +bool ThreadSuspender::SuspendThread(ThreadID tid) { int pterrno; if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr), &pterrno)) { @@ -210,7 +210,7 @@ void ThreadSuspender::KillAllThreads() { bool ThreadSuspender::SuspendAllThreads() { ThreadLister thread_lister(pid_); bool retry = true; - InternalMmapVector threads; + InternalMmapVector threads; threads.reserve(128); for (int i = 0; i < 30 && retry; ++i) { retry = false; @@ -226,7 +226,7 @@ bool ThreadSuspender::SuspendAllThreads() { case ThreadLister::Ok: break; } - for (tid_t tid : threads) { + for (ThreadID tid : threads) { // Are we already attached to this thread? // Currently this check takes linear time, however the number of threads // is usually small. @@ -403,7 +403,77 @@ struct ScopedSetTracerPID { } }; +// This detects whether ptrace is blocked (e.g., by seccomp), by forking and +// then attempting ptrace. +// This separate check is necessary because StopTheWorld() creates a thread +// with a shared virtual address space and shared TLS, and therefore +// cannot use waitpid() due to the shared errno. +static void TestPTrace() { +# if SANITIZER_SPARC + // internal_fork() on SPARC actually calls __fork(). We can't safely fork, + // because it's possible seccomp has been configured to disallow fork() but + // allow clone(). + VReport(1, "WARNING: skipping TestPTrace() because this is SPARC\n"); + VReport(1, + "If seccomp blocks ptrace, LeakSanitizer may hang without further " + "notice\n"); + VReport( + 1, + "If seccomp does not block ptrace, you can safely ignore this warning\n"); +# else + // Heuristic: only check the first time this is called. This is not always + // correct (e.g., user manually triggers leak detection, then updates + // seccomp, then leak detection is triggered again). + static bool checked = false; + if (checked) + return; + checked = true; + + // Hopefully internal_fork() is not too expensive, thanks to copy-on-write. + // Besides, this is only called the first time. + // Note that internal_fork() on non-SPARC Linux actually calls + // SYSCALL(clone); thus, it is reasonable to use it because if seccomp kills + // TestPTrace(), it would have killed StopTheWorld() anyway. + int pid = internal_fork(); + + if (pid < 0) { + int rverrno; + if (internal_iserror(pid, &rverrno)) + VReport(0, "WARNING: TestPTrace() failed to fork (errno %d)\n", rverrno); + + // We don't abort the sanitizer - it's still worth letting the sanitizer + // try. + return; + } + + if (pid == 0) { + // Child subprocess + + // TODO: consider checking return value of internal_ptrace, to handle + // SCMP_ACT_ERRNO. However, be careful not to consume too many + // resources performing a proper ptrace. + internal_ptrace(PTRACE_ATTACH, 0, nullptr, nullptr); + internal__exit(0); + } else { + int wstatus; + internal_waitpid(pid, &wstatus, 0); + + // Handle SCMP_ACT_KILL + if (WIFSIGNALED(wstatus)) { + VReport(0, + "WARNING: ptrace appears to be blocked (is seccomp enabled?). " + "LeakSanitizer may hang.\n"); + VReport(0, "Child exited with signal %d.\n", WTERMSIG(wstatus)); + // We don't abort the sanitizer - it's still worth letting the sanitizer + // try. + } + } +# endif +} + void StopTheWorld(StopTheWorldCallback callback, void *argument) { + TestPTrace(); + StopTheWorldScope in_stoptheworld; // Prepare the arguments for TracerThread. struct TracerThreadArgument tracer_thread_argument; @@ -457,7 +527,8 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0); // Allow the tracer thread to start. tracer_thread_argument.mutex.Unlock(); - // NOTE: errno is shared between this thread and the tracer thread. + // NOTE: errno is shared between this thread and the tracer thread + // (clone was called without CLONE_SETTLS / newtls). // internal_waitpid() may call syscall() which can access/spoil errno, // so we can't call it now. Instead we for the tracer thread to finish using // the spin loop below. Man page for sched_yield() says "In the Linux @@ -546,7 +617,7 @@ static constexpr uptr kExtraRegs[] = {0}; #error "Unsupported architecture" #endif // SANITIZER_ANDROID && defined(__arm__) -tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const { +ThreadID SuspendedThreadsListLinux::GetThreadID(uptr index) const { CHECK_LT(index, thread_ids_.size()); return thread_ids_[index]; } @@ -555,14 +626,14 @@ uptr SuspendedThreadsListLinux::ThreadCount() const { return thread_ids_.size(); } -bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const { +bool SuspendedThreadsListLinux::ContainsTid(ThreadID thread_id) const { for (uptr i = 0; i < thread_ids_.size(); i++) { if (thread_ids_[i] == thread_id) return true; } return false; } -void SuspendedThreadsListLinux::Append(tid_t tid) { +void SuspendedThreadsListLinux::Append(ThreadID tid) { thread_ids_.push_back(tid); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp index 813616467656b..d6ef37ac847ce 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp @@ -23,7 +23,7 @@ namespace __sanitizer { typedef struct { - tid_t tid; + ThreadID tid; thread_t thread; } SuspendedThreadInfo; @@ -31,7 +31,7 @@ class SuspendedThreadsListMac final : public SuspendedThreadsList { public: SuspendedThreadsListMac() = default; - tid_t GetThreadID(uptr index) const override; + ThreadID GetThreadID(uptr index) const override; thread_t GetThread(uptr index) const; uptr ThreadCount() const override; bool ContainsThread(thread_t thread) const; @@ -111,7 +111,7 @@ typedef x86_thread_state32_t regs_struct; #error "Unsupported architecture" #endif -tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { +ThreadID SuspendedThreadsListMac::GetThreadID(uptr index) const { CHECK_LT(index, threads_.size()); return threads_[index].tid; } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp index 58a0cfdbf9d48..33d603fec800a 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp @@ -52,17 +52,17 @@ class SuspendedThreadsListNetBSD final : public SuspendedThreadsList { public: SuspendedThreadsListNetBSD() { thread_ids_.reserve(1024); } - tid_t GetThreadID(uptr index) const; + ThreadID GetThreadID(uptr index) const; uptr ThreadCount() const; - bool ContainsTid(tid_t thread_id) const; - void Append(tid_t tid); + bool ContainsTid(ThreadID thread_id) const; + void Append(ThreadID tid); PtraceRegistersStatus GetRegistersAndSP(uptr index, InternalMmapVector *buffer, uptr *sp) const; private: - InternalMmapVector thread_ids_; + InternalMmapVector thread_ids_; }; struct TracerThreadArgument { @@ -313,7 +313,7 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { } } -tid_t SuspendedThreadsListNetBSD::GetThreadID(uptr index) const { +ThreadID SuspendedThreadsListNetBSD::GetThreadID(uptr index) const { CHECK_LT(index, thread_ids_.size()); return thread_ids_[index]; } @@ -322,7 +322,7 @@ uptr SuspendedThreadsListNetBSD::ThreadCount() const { return thread_ids_.size(); } -bool SuspendedThreadsListNetBSD::ContainsTid(tid_t thread_id) const { +bool SuspendedThreadsListNetBSD::ContainsTid(ThreadID thread_id) const { for (uptr i = 0; i < thread_ids_.size(); i++) { if (thread_ids_[i] == thread_id) return true; @@ -330,7 +330,7 @@ bool SuspendedThreadsListNetBSD::ContainsTid(tid_t thread_id) const { return false; } -void SuspendedThreadsListNetBSD::Append(tid_t tid) { +void SuspendedThreadsListNetBSD::Append(ThreadID tid) { thread_ids_.push_back(tid); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp index fa15f8a9f06a9..43df59544d304 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp @@ -38,7 +38,7 @@ struct SuspendedThreadsListWindows final : public SuspendedThreadsList { InternalMmapVector *buffer, uptr *sp) const override; - tid_t GetThreadID(uptr index) const override; + ThreadID GetThreadID(uptr index) const override; uptr ThreadCount() const override; }; @@ -68,7 +68,7 @@ PtraceRegistersStatus SuspendedThreadsListWindows::GetRegistersAndSP( return REGISTERS_AVAILABLE; } -tid_t SuspendedThreadsListWindows::GetThreadID(uptr index) const { +ThreadID SuspendedThreadsListWindows::GetThreadID(uptr index) const { CHECK_LT(index, threadIds.size()); return threadIds[index]; } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h index d6d57590908a2..f6c1cff0548f8 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -84,7 +84,7 @@ class SymbolizerProcess { const char *SendCommand(const char *command); protected: - ~SymbolizerProcess() {} + ~SymbolizerProcess(); /// The maximum number of arguments required to invoke a tool process. static const unsigned kArgVMax = 16; @@ -115,6 +115,10 @@ class SymbolizerProcess { fd_t input_fd_; fd_t output_fd_; + // We hold on to the child's stdin fd (the read end of the pipe) + // so that when we write to it, we don't get a SIGPIPE + fd_t child_stdin_fd_; + InternalMmapVector buffer_; static const uptr kMaxTimesRestarted = 5; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp index 70036f25d8b37..85073e4b1ecb0 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp @@ -477,10 +477,11 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, return symbolizer_process_->SendCommand(buffer_); } -SymbolizerProcess::SymbolizerProcess(const char *path, bool use_posix_spawn) +SymbolizerProcess::SymbolizerProcess(const char* path, bool use_posix_spawn) : path_(path), input_fd_(kInvalidFd), output_fd_(kInvalidFd), + child_stdin_fd_(kInvalidFd), times_restarted_(0), failed_to_start_(false), reported_invalid_path_(false), @@ -489,6 +490,11 @@ SymbolizerProcess::SymbolizerProcess(const char *path, bool use_posix_spawn) CHECK_NE(path_[0], '\0'); } +SymbolizerProcess::~SymbolizerProcess() { + if (child_stdin_fd_ != kInvalidFd) + CloseFile(child_stdin_fd_); +} + static bool IsSameModule(const char *path) { if (const char *ProcessName = GetProcessName()) { if (const char *SymbolizerName = StripModuleName(path)) { @@ -534,6 +540,10 @@ bool SymbolizerProcess::Restart() { CloseFile(input_fd_); if (output_fd_ != kInvalidFd) CloseFile(output_fd_); + if (child_stdin_fd_ != kInvalidFd) { + CloseFile(child_stdin_fd_); + child_stdin_fd_ = kInvalidFd; // Don't free in destructor + } return StartSymbolizerSubprocess(); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp index 88536fc4e6222..d3259984b18a7 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -78,13 +78,25 @@ class AtosSymbolizerProcess final : public SymbolizerProcess { } bool ReachedEndOfOutput(const char *buffer, uptr length) const override { - return (length >= 1 && buffer[length - 1] == '\n'); + if (common_flags()->symbolize_inline_frames) { + // When running with -i, atos sends two newlines at the end of each + // address it symbolizes. This indicates the end of the set of frames + // for a particular address. + return length >= 2 && buffer[length - 1] == '\n' && + buffer[length - 2] == '\n'; + } else { + // When running without -i, atos only sends a single newline at + // the end of each address it symbolizes. + return length >= 1 && buffer[length - 1] == '\n'; + } } void GetArgV(const char *path_to_binary, const char *(&argv)[kArgVMax]) const override { int i = 0; argv[i++] = path_to_binary; + if (common_flags()->symbolize_inline_frames) + argv[i++] = "-i"; argv[i++] = "-p"; argv[i++] = &pid_str_[0]; if (GetMacosAlignedVersion() == MacosVersion(10, 9)) { @@ -102,12 +114,16 @@ class AtosSymbolizerProcess final : public SymbolizerProcess { #undef K_ATOS_ENV_VAR -static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, - char **out_module, char **out_file, uptr *line, - uptr *start_address) { +// Parses a single frame (one line) from str, and returns the pointer to the +// next character to parse (i.e. after the newline) if successful. If +// it fails, returns NULL. +static const char* ParseCommandOutput(const char* str, uptr addr, + char** out_name, char** out_module, + char** out_file, uptr* line, + uptr* start_address) { // Trim ending newlines. char *trim; - ExtractTokenUpToDelimiter(str, "\n", &trim); + str = ExtractTokenUpToDelimiter(str, "\n", &trim); // The line from `atos` is in one of these formats: // myfunction (in library.dylib) (sourcefile.c:17) @@ -124,7 +140,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, if (rest[0] == '\0') { InternalFree(symbol_name); InternalFree(trim); - return false; + return NULL; } if (internal_strncmp(symbol_name, "0x", 2) != 0) @@ -149,7 +165,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, } InternalFree(trim); - return true; + return str; } AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) @@ -161,31 +177,72 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { char command[32]; internal_snprintf(command, sizeof(command), "0x%zx\n", addr); const char *buf = process_->SendCommand(command); - if (!buf) return false; - uptr line; - uptr start_address = AddressInfo::kUnknown; - if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module, - &stack->info.file, &line, &start_address)) { - Report("WARNING: atos failed to symbolize address \"0x%zx\"\n", addr); + if (!buf) return false; - } - stack->info.line = (int)line; - - if (start_address == AddressInfo::kUnknown) { - // Fallback to dladdr() to get function start address if atos doesn't report - // it. - Dl_info info; - int result = dladdr((const void *)addr, &info); - if (result) - start_address = reinterpret_cast(info.dli_saddr); - } - // Only assign to `function_offset` if we were able to get the function's - // start address and we got a sensible `start_address` (dladdr doesn't always - // ensure that `addr >= sym_addr`). - if (start_address != AddressInfo::kUnknown && addr >= start_address) { - stack->info.function_offset = addr - start_address; + SymbolizedStack* last = stack; + bool top_frame = true; + + // Parse one line of input (i.e. one frame). + // + // When symbolize_inline_frames=true, an empty line + // (i.e. \n at the beginning of a line) indicates that the last + // frame has been sent. + // + // When symbolize_inline_frames=false, the symbolizer will send only + // one frame (without a empty line), so loop runs exactly once + // and hits an early `break`. + while (*buf != '\n') { + uptr line; + uptr start_address = AddressInfo::kUnknown; + + SymbolizedStack* cur; + if (top_frame) { + cur = stack; + } else { + cur = SymbolizedStack::New(stack->info.address); + cur->info.FillModuleInfo(stack->info.module, stack->info.module_offset, + stack->info.module_arch); + last->next = cur; + last = cur; + } + + // Parse one line of input (i.e. one frame) + // If this succeeds, buf will be updated to point to the first character + // after the newline. + buf = ParseCommandOutput(buf, addr, &cur->info.function, &cur->info.module, + &cur->info.file, &line, &start_address); + + // Upon failure, ParseCommandOutput returns NULL. + if (!buf) { + Report("WARNING: atos failed to symbolize address \"0x%zx\"\n", addr); + return false; + } + cur->info.line = (int)line; + + if (top_frame && start_address == AddressInfo::kUnknown) { + // Fallback to dladdr() to get function start address if atos doesn't + // report it. + Dl_info info; + int result = dladdr((const void*)addr, &info); + if (result) + start_address = reinterpret_cast(info.dli_saddr); + } + + // Only assign to `function_offset` if we were able to get the function's + // start address and we got a sensible `start_address` (dladdr doesn't + // always ensure that `addr >= sym_addr`). + if (start_address != AddressInfo::kUnknown && addr >= start_address) { + cur->info.function_offset = addr - start_address; + } + + // atos only sends one line when inline frames are off + if (!common_flags()->symbolize_inline_frames) + break; + + top_frame = false; } + return true; } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index 4475a095f786f..2510d1b8b0cd1 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -156,30 +156,34 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { Printf("\n"); } + fd_t infd[2] = {}, outfd[2] = {}; + if (!CreateTwoHighNumberedPipes(infd, outfd)) { + Report( + "WARNING: Can't create a socket pair to start " + "external symbolizer (errno: %d)\n", + errno); + return false; + } + if (use_posix_spawn_) { # if SANITIZER_APPLE - fd_t fd = internal_spawn(argv, const_cast(GetEnvP()), &pid); - if (fd == kInvalidFd) { + bool success = internal_spawn(argv, const_cast(GetEnvP()), + &pid, outfd[0], infd[1]); + if (!success) { Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", errno); + internal_close(infd[0]); + internal_close(outfd[1]); return false; } - input_fd_ = fd; - output_fd_ = fd; + // We intentionally hold on to the read-end so that we don't get a SIGPIPE + child_stdin_fd_ = outfd[0]; + # else // SANITIZER_APPLE UNIMPLEMENTED(); # endif // SANITIZER_APPLE } else { - fd_t infd[2] = {}, outfd[2] = {}; - if (!CreateTwoHighNumberedPipes(infd, outfd)) { - Report( - "WARNING: Can't create a socket pair to start " - "external symbolizer (errno: %d)\n", - errno); - return false; - } - pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0], /* stdout */ infd[1]); if (pid < 0) { @@ -187,11 +191,11 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { internal_close(outfd[1]); return false; } - - input_fd_ = infd[0]; - output_fd_ = outfd[1]; } + input_fd_ = infd[0]; + output_fd_ = outfd[1]; + CHECK_GT(pid, 0); // Check that symbolizer subprocess started successfully. @@ -507,6 +511,13 @@ static void ChooseSymbolizerTools(IntrusiveList *list, } # if SANITIZER_APPLE + if (list->empty()) { + Report( + "WARN: No external symbolizers found. Symbols may be missing or " + "unreliable.\n"); + Report( + "HINT: Is PATH set? Does sandbox allow file-read of /usr/bin/atos?\n"); + } VReport(2, "Using dladdr symbolizer.\n"); list->push_back(new (*allocator) DlAddrSymbolizer()); # endif // SANITIZER_APPLE diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp index cdc24f4a8869c..d726d282437ca 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.cpp @@ -80,7 +80,7 @@ void ThreadContextBase::SetFinished() { OnFinished(); } -void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type, +void ThreadContextBase::SetStarted(ThreadID _os_id, ThreadType _thread_type, void *arg) { status = ThreadStatusRunning; os_id = _os_id; @@ -228,7 +228,8 @@ static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx, tctx->status != ThreadStatusDead); } -ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) { +ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked( + ThreadID os_id) { return FindThreadContextLocked(FindThreadContextByOsIdCallback, (void *)os_id); } @@ -322,8 +323,8 @@ ThreadStatus ThreadRegistry::FinishThread(u32 tid) { return prev_status; } -void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type, - void *arg) { +void ThreadRegistry::StartThread(u32 tid, ThreadID os_id, + ThreadType thread_type, void *arg) { ThreadRegistryLock l(this); running_threads_++; ThreadContextBase *tctx = threads_[tid]; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h index f548132a6fe4f..1003205de0130 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h @@ -43,7 +43,7 @@ class ThreadContextBase { const u32 tid; // Thread ID. Main thread should have tid = 0. u64 unique_id; // Unique thread ID. u32 reuse_count; // Number of times this tid was reused. - tid_t os_id; // PID (used for reporting). + ThreadID os_id; // PID (used for reporting). uptr user_id; // Some opaque user thread id (e.g. pthread_t). char name[64]; // As annotated by user. @@ -62,7 +62,7 @@ class ThreadContextBase { void SetDead(); void SetJoined(void *arg); void SetFinished(); - void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg); + void SetStarted(ThreadID _os_id, ThreadType _thread_type, void *arg); void SetCreated(uptr _user_id, u64 _unique_id, bool _detached, u32 _parent_tid, u32 _stack_tid, void *arg); void Reset(); @@ -126,7 +126,7 @@ class SANITIZER_MUTEX ThreadRegistry { // is found. ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb, void *arg); - ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id); + ThreadContextBase *FindThreadContextByOsIDLocked(ThreadID os_id); void SetThreadName(u32 tid, const char *name); void SetThreadNameByUserId(uptr user_id, const char *name); @@ -134,7 +134,7 @@ class SANITIZER_MUTEX ThreadRegistry { void JoinThread(u32 tid, void *arg); // Finishes thread and returns previous status. ThreadStatus FinishThread(u32 tid); - void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg); + void StartThread(u32 tid, ThreadID os_id, ThreadType thread_type, void *arg); u32 ConsumeThreadUserId(uptr user_id); void SetThreadUserId(u32 tid, uptr user_id); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp index 48ebe78c4031e..ed4f60deeffc8 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -108,9 +108,7 @@ int internal_dlinfo(void *handle, int request, void *p) { // In contrast to POSIX, on Windows GetCurrentThreadId() // returns a system-unique identifier. -tid_t GetTid() { - return GetCurrentThreadId(); -} +ThreadID GetTid() { return GetCurrentThreadId(); } uptr GetThreadSelf() { return GetTid(); diff --git a/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp index ebc36a8583e05..6d1a5281b41ff 100644 --- a/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp +++ b/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp @@ -12,6 +12,22 @@ static void message(const char *msg) { ubsan_message(msg); } static void message(const char *msg) { (void)write(2, msg, strlen(msg)); } #endif +// If for some reason we cannot build the runtime with preserve_all, don't +// emit any symbol. Programs that need them will fail to link, but that is +// better than randomly corrupted registers. +// Some architectures don't support preserve_all (but clang still has the) +// attribute. For now, only support x86-64 and aarch64. +#if defined(__clang__) && defined(__has_cpp_attribute) && \ + (defined(__x86_64__) || defined(__aarch64__)) +#if __has_cpp_attribute(clang::preserve_all) +#define PRESERVE_HANDLERS true +#else +#define PRESERVE_HANDLERS false +#endif +#else +#define PRESERVE_HANDLERS false +#endif + static const int kMaxCallerPcs = 20; static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs]; // Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means @@ -85,6 +101,18 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind, } } +#if PRESERVE_HANDLERS +SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_preserve, + const char *kind, uintptr_t caller) +[[clang::preserve_all]] { + // Additional indirecton so the user can override this with their own + // preserve_all function. This would allow, e.g., a function that reports the + // first error only, so for all subsequent calls we can skip the register save + // / restore. + __ubsan_report_error(kind, caller); +} +#endif + SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_fatal, const char *kind, uintptr_t caller) { // Use another handlers, in case it's already overriden. @@ -119,10 +147,21 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { #define INTERFACE extern "C" __attribute__((visibility("default"))) +#if PRESERVE_HANDLERS +#define HANDLER_PRESERVE(name, kind) \ + INTERFACE void __ubsan_handle_##name##_minimal_preserve() \ + [[clang::preserve_all]] { \ + __ubsan_report_error_preserve(kind, GET_CALLER_PC()); \ + } +#else +#define HANDLER_PRESERVE(name, kind) +#endif + #define HANDLER_RECOVER(name, kind) \ INTERFACE void __ubsan_handle_##name##_minimal() { \ __ubsan_report_error(kind, GET_CALLER_PC()); \ - } + } \ + HANDLER_PRESERVE(name, kind) #define HANDLER_NORECOVER(name, kind) \ INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ From a6cb595deee3194169346163964ac9fb733f492a Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 3 Jul 2026 06:31:39 +0000 Subject: [PATCH 2/5] Fix -Wformat warning for %zx with pointer argument https://github.com/llvm/llvm-project/commit/457b14c327d814fd80316f977cf7b1eafc488632 introduced a -Wformat warning, which is an error for us because we use `-Werror`. This warning was fixed later (after LLVM 22 release) in https://github.com/llvm/llvm-project/commit/0e5ab0f4f412a30751bea9d83cb97e0d754bc032, so this applies the fix sooner to fix the error. --- system/lib/compiler-rt/lib/asan/asan_fake_stack.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/lib/compiler-rt/lib/asan/asan_fake_stack.cpp b/system/lib/compiler-rt/lib/asan/asan_fake_stack.cpp index af73d31b8a5dc..9622881839e38 100644 --- a/system/lib/compiler-rt/lib/asan/asan_fake_stack.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_fake_stack.cpp @@ -77,11 +77,11 @@ FakeStack* FakeStack::Create(uptr stack_size_log) { VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; " "mmapped %zdK, noreserve=%d, true_start: %p, start of first frame: " - "0x%zx\n", + "%p\n", GetCurrentTidOrInvalid(), (void*)p, (void*)(p + FakeStack::RequiredSize(stack_size_log)), stack_size_log, size >> 10, flags()->uar_noreserve, res->true_start, - res->GetFrame(stack_size_log, /*class_id*/ 0, /*pos*/ 0)); + (void*)res->GetFrame(stack_size_log, /*class_id*/ 0, /*pos*/ 0)); return res; } From eb8b6bd6a1a8383206ce0ceb3d9058a3fd1c9483 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 3 Jul 2026 06:36:25 +0000 Subject: [PATCH 3/5] Rename tid_t to ThreadID https://github.com/llvm/llvm-project/commit/8e072b9d495293b08d939c880d185025751b4269 renamed `tid_t` to `ThreadID`. This applies it in Emscripten-specific code too. --- system/lib/compiler-rt/lib/lsan/lsan_common.cpp | 2 +- system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp | 4 ++-- .../compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common.cpp index 114710fb500ac..120a1d959b565 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_common.cpp @@ -454,7 +454,7 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls( # endif #if SANITIZER_EMSCRIPTEN -void ProcessThreads(SuspendedThreadsList const &, Frontier *, tid_t, uptr); +void ProcessThreads(SuspendedThreadsList const &, Frontier *, ThreadID, uptr); #else static void ProcessThreadRegistry(Frontier *frontier) { InternalMmapVector ptrs; diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp index 8dae57970d363..8297e9f997e6d 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp @@ -123,7 +123,7 @@ static void ProcessThreadsCallback(ThreadContextBase *tctx, void *arg) { return; Frontier *frontier = reinterpret_cast(arg); - tid_t os_id = tctx->os_id; + ThreadID os_id = tctx->os_id; uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; DTLS *dtls; @@ -175,7 +175,7 @@ static void ProcessThreadsCallback(ThreadContextBase *tctx, void *arg) { void ProcessThreads(SuspendedThreadsList const& suspended_threads, Frontier* frontier, - tid_t caller_tid, + ThreadID caller_tid, uptr caller_sp) { GetThreadRegistryLocked()->RunCallbackForEachThreadLocked( ProcessThreadsCallback, frontier); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp index 9481f6a6fe77e..84b4a4314d433 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp @@ -202,7 +202,7 @@ void internal__exit(int exitcode) { _exit(exitcode); } -tid_t GetTid() { +ThreadID GetTid() { return gettid(); } From e8c6093930c1392363600772c98ca35533c5336c Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 3 Jul 2026 07:18:00 +0000 Subject: [PATCH 4/5] ChangeLog and readme --- ChangeLog.md | 1 + system/lib/compiler-rt/readme.txt | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index e97b4adad87f5..906653126deb5 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -34,6 +34,7 @@ See docs/process.md for more on how version tagging works. FS-backend handler signature changed from `poll(stream, timeout)` to `poll(stream)` returning the current readiness mask; out-of-tree custom FS backends with a `poll` handler must update. (#27226) +- compiler-rt was updated to LLVM 22.1.8. (#27245) 6.0.2 - 07/01/26 ---------------- diff --git a/system/lib/compiler-rt/readme.txt b/system/lib/compiler-rt/readme.txt index 8f2fe7cbebeb6..f839784110c67 100644 --- a/system/lib/compiler-rt/readme.txt +++ b/system/lib/compiler-rt/readme.txt @@ -1,14 +1,14 @@ LLVM's compiler-rt ------------------ -These files are from the llvm-project based on release 21.1.8. +These files are from the llvm-project based on release 22.1.8. We maintain a local fork of llvm-project that contains any Emscripten specific patches: https://github.com/emscripten-core/llvm-project -The current patch is based on the emscripten-libs-21 branch. +The current patch is based on the emscripten-libs-22 branch. Update Instructions ------------------- @@ -20,4 +20,4 @@ Modifications For a list of changes from upstream see the compiler-rt files that are part of: -https://github.com/llvm/llvm-project/compare/llvmorg-21.1.8...emscripten-core:emscripten-libs-21 +https://github.com/llvm/llvm-project/compare/llvmorg-22.1.8...emscripten-core:emscripten-libs-22 From 6fe1c44719ba5f8202c14e6be0724ba46adb74c8 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 3 Jul 2026 08:37:10 +0000 Subject: [PATCH 5/5] Add a new file --- system/lib/compiler-rt/lib/asan/asan_aix.cpp | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 system/lib/compiler-rt/lib/asan/asan_aix.cpp diff --git a/system/lib/compiler-rt/lib/asan/asan_aix.cpp b/system/lib/compiler-rt/lib/asan/asan_aix.cpp new file mode 100644 index 0000000000000..58a79ea5e7479 --- /dev/null +++ b/system/lib/compiler-rt/lib/asan/asan_aix.cpp @@ -0,0 +1,48 @@ +//===-- asan_aix.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// AIX-specific details. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_AIX +# include "asan_mapping.h" +# include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __asan { + +void TryReExecWithoutASLR() { + // Allowed to fail and do nothing. +} + +void AsanCheckIncompatibleRT() {} + +void AsanCheckDynamicRTPrereqs() {} + +void InitializePlatformExceptionHandlers() {} + +void* AsanDoesNotSupportStaticLinkage() { return 0; } + +void InitializePlatformInterceptors() {} +void AsanApplyToGlobals(globals_op_fptr op, const void* needle) {} + +uptr FindDynamicShadowStart() { + UNREACHABLE("AIX does not use dynamic shadow offset!"); + return 0; +} + +void FlushUnneededASanShadowMemory(uptr p, uptr size) { + ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); +} + +} // namespace __asan + +#endif // SANITIZER_AIX