diff options
author | Martin Liska <mliska@suse.cz> | 2020-10-16 10:03:04 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2020-10-16 10:57:03 +0200 |
commit | 0b997f6e07771c98178ea09f4a8c4446baaf84da (patch) | |
tree | c3ef933f3fda4195644c6734b2c212e9f77718e3 /libsanitizer/sanitizer_common | |
parent | 4a70aa7a627c0b918ce1da75c0dbe088539e420f (diff) | |
download | gcc-0b997f6e07771c98178ea09f4a8c4446baaf84da.zip gcc-0b997f6e07771c98178ea09f4a8c4446baaf84da.tar.gz gcc-0b997f6e07771c98178ea09f4a8c4446baaf84da.tar.bz2 |
libsanitizer: merge from master
Diffstat (limited to 'libsanitizer/sanitizer_common')
66 files changed, 1833 insertions, 521 deletions
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp index ec77b9c..3157b35 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp @@ -137,8 +137,14 @@ static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { #endif // SANITIZER_GO || defined(SANITIZER_USE_MALLOC) +namespace { const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull; +struct BlockHeader { + u64 magic; +}; +} // namespace + static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) { SetAllocatorOutOfMemory(); Report("FATAL: %s: internal allocator is out of memory trying to allocate " @@ -147,27 +153,28 @@ static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) { } void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) { - if (size + sizeof(u64) < size) + uptr s = size + sizeof(BlockHeader); + if (s < size) return nullptr; - void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment); + BlockHeader *p = (BlockHeader *)RawInternalAlloc(s, cache, alignment); if (UNLIKELY(!p)) - ReportInternalAllocatorOutOfMemory(size + sizeof(u64)); - ((u64*)p)[0] = kBlockMagic; - return (char*)p + sizeof(u64); + ReportInternalAllocatorOutOfMemory(s); + p->magic = kBlockMagic; + return p + 1; } void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { if (!addr) return InternalAlloc(size, cache); - if (size + sizeof(u64) < size) + uptr s = size + sizeof(BlockHeader); + if (s < size) return nullptr; - addr = (char*)addr - sizeof(u64); - size = size + sizeof(u64); - CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); - void *p = RawInternalRealloc(addr, size, cache); + BlockHeader *p = (BlockHeader *)addr - 1; + CHECK_EQ(kBlockMagic, p->magic); + p = (BlockHeader *)RawInternalRealloc(p, s, cache); if (UNLIKELY(!p)) - ReportInternalAllocatorOutOfMemory(size); - return (char*)p + sizeof(u64); + ReportInternalAllocatorOutOfMemory(s); + return p + 1; } void *InternalReallocArray(void *addr, uptr count, uptr size, @@ -198,10 +205,10 @@ void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { void InternalFree(void *addr, InternalAllocatorCache *cache) { if (!addr) return; - addr = (char*)addr - sizeof(u64); - CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); - ((u64*)addr)[0] = 0; - RawInternalFree(addr, cache); + BlockHeader *p = (BlockHeader *)addr - 1; + CHECK_EQ(kBlockMagic, p->magic); + p->magic = 0; + RawInternalFree(p, cache); } // LowLevelAllocator diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.h b/libsanitizer/sanitizer_common/sanitizer_allocator.h index 23d5898..5ec4741 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator.h @@ -52,14 +52,14 @@ struct NoOpMapUnmapCallback { // Callback type for iterating over chunks. typedef void (*ForEachChunkCallback)(uptr chunk, void *arg); -INLINE u32 Rand(u32 *state) { // ANSI C linear congruential PRNG. +inline u32 Rand(u32 *state) { // ANSI C linear congruential PRNG. return (*state = *state * 1103515245 + 12345) >> 16; } -INLINE u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n) +inline u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n) template<typename T> -INLINE void RandomShuffle(T *a, u32 n, u32 *rand_state) { +inline void RandomShuffle(T *a, u32 n, u32 *rand_state) { if (n <= 1) return; u32 state = *rand_state; for (u32 i = n - 1; i > 0; i--) diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h b/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h index fc426f0..1cc3992 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h @@ -27,7 +27,7 @@ namespace __sanitizer { void SetErrnoToENOMEM(); // A common errno setting logic shared by almost all sanitizer allocator APIs. -INLINE void *SetErrnoOnNull(void *ptr) { +inline void *SetErrnoOnNull(void *ptr) { if (UNLIKELY(!ptr)) SetErrnoToENOMEM(); return ptr; @@ -41,7 +41,7 @@ INLINE void *SetErrnoOnNull(void *ptr) { // two and that the size is a multiple of alignment for POSIX implementation, // and a bit relaxed requirement for non-POSIX ones, that the size is a multiple // of alignment. -INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { +inline bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { #if SANITIZER_POSIX return alignment != 0 && IsPowerOfTwo(alignment) && (size & (alignment - 1)) == 0; @@ -52,13 +52,13 @@ INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { // Checks posix_memalign() parameters, verifies that alignment is a power of two // and a multiple of sizeof(void *). -INLINE bool CheckPosixMemalignAlignment(uptr alignment) { +inline bool CheckPosixMemalignAlignment(uptr alignment) { return alignment != 0 && IsPowerOfTwo(alignment) && (alignment % sizeof(void *)) == 0; } // Returns true if calloc(size, n) call overflows on size*n calculation. -INLINE bool CheckForCallocOverflow(uptr size, uptr n) { +inline bool CheckForCallocOverflow(uptr size, uptr n) { if (!size) return false; uptr max = (uptr)-1L; @@ -67,7 +67,7 @@ INLINE bool CheckForCallocOverflow(uptr size, uptr n) { // Returns true if the size passed to pvalloc overflows when rounded to the next // multiple of page_size. -INLINE bool CheckForPvallocOverflow(uptr size, uptr page_size) { +inline bool CheckForPvallocOverflow(uptr size, uptr page_size) { return RoundUpTo(size, page_size) < size; } diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h index 3b1838b..b90dabb 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h @@ -153,6 +153,7 @@ class SizeClassAllocator32 { } void *GetMetaData(const void *p) { + CHECK(kMetadataSize); CHECK(PointerIsMine(p)); uptr mem = reinterpret_cast<uptr>(p); uptr beg = ComputeRegionBeg(mem); diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h index 1d9a29c..0a18b0c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h @@ -186,13 +186,13 @@ class SizeClassAllocator64 { void *GetBlockBegin(const void *p) { uptr class_id = GetSizeClass(p); + if (class_id >= kNumClasses) return nullptr; uptr size = ClassIdToSize(class_id); if (!size) return nullptr; uptr chunk_idx = GetChunkIdx((uptr)p, size); uptr reg_beg = GetRegionBegin(p); uptr beg = chunk_idx * size; uptr next_beg = beg + size; - if (class_id >= kNumClasses) return nullptr; const RegionInfo *region = AddressSpaceView::Load(GetRegionInfo(class_id)); if (region->mapped_user >= next_beg) return reinterpret_cast<void*>(reg_beg + beg); @@ -207,6 +207,7 @@ class SizeClassAllocator64 { static uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); } void *GetMetaData(const void *p) { + CHECK(kMetadataSize); uptr class_id = GetSizeClass(p); uptr size = ClassIdToSize(class_id); uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size); diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h index 1d128f5..61fb987 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h @@ -18,8 +18,8 @@ // (currently, 32 bits and internal allocator). class LargeMmapAllocatorPtrArrayStatic { public: - INLINE void *Init() { return &p_[0]; } - INLINE void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); } + inline void *Init() { return &p_[0]; } + inline void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); } private: static const int kMaxNumChunks = 1 << 15; uptr p_[kMaxNumChunks]; @@ -31,14 +31,14 @@ class LargeMmapAllocatorPtrArrayStatic { // same functionality in Fuchsia case, which does not support MAP_NORESERVE. class LargeMmapAllocatorPtrArrayDynamic { public: - INLINE void *Init() { + inline void *Init() { uptr p = address_range_.Init(kMaxNumChunks * sizeof(uptr), SecondaryAllocatorName); CHECK(p); return reinterpret_cast<void*>(p); } - INLINE void EnsureSpace(uptr n) { + inline void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); DCHECK(n <= n_reserved_); if (UNLIKELY(n == n_reserved_)) { diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic.h b/libsanitizer/sanitizer_common/sanitizer_atomic.h index a798a0c..46f0695 100644 --- a/libsanitizer/sanitizer_common/sanitizer_atomic.h +++ b/libsanitizer/sanitizer_common/sanitizer_atomic.h @@ -72,12 +72,12 @@ namespace __sanitizer { // Clutter-reducing helpers. template<typename T> -INLINE typename T::Type atomic_load_relaxed(const volatile T *a) { +inline typename T::Type atomic_load_relaxed(const volatile T *a) { return atomic_load(a, memory_order_relaxed); } template<typename T> -INLINE void atomic_store_relaxed(volatile T *a, typename T::Type v) { +inline void atomic_store_relaxed(volatile T *a, typename T::Type v) { atomic_store(a, v, memory_order_relaxed); } diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h index c40461e..fc13ca5 100644 --- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h @@ -34,16 +34,16 @@ namespace __sanitizer { // See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html // for mappings of the memory model to different processors. -INLINE void atomic_signal_fence(memory_order) { +inline void atomic_signal_fence(memory_order) { __asm__ __volatile__("" ::: "memory"); } -INLINE void atomic_thread_fence(memory_order) { +inline void atomic_thread_fence(memory_order) { __sync_synchronize(); } template<typename T> -INLINE typename T::Type atomic_fetch_add(volatile T *a, +inline typename T::Type atomic_fetch_add(volatile T *a, typename T::Type v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -51,7 +51,7 @@ INLINE typename T::Type atomic_fetch_add(volatile T *a, } template<typename T> -INLINE typename T::Type atomic_fetch_sub(volatile T *a, +inline typename T::Type atomic_fetch_sub(volatile T *a, typename T::Type v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -59,7 +59,7 @@ INLINE typename T::Type atomic_fetch_sub(volatile T *a, } template<typename T> -INLINE typename T::Type atomic_exchange(volatile T *a, +inline typename T::Type atomic_exchange(volatile T *a, typename T::Type v, memory_order mo) { DCHECK(!((uptr)a % sizeof(*a))); if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst)) @@ -71,7 +71,7 @@ INLINE typename T::Type atomic_exchange(volatile T *a, } template <typename T> -INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, +inline bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, typename T::Type xchg, memory_order mo) { typedef typename T::Type Type; @@ -84,7 +84,7 @@ INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, } template<typename T> -INLINE bool atomic_compare_exchange_weak(volatile T *a, +inline bool atomic_compare_exchange_weak(volatile T *a, typename T::Type *cmp, typename T::Type xchg, memory_order mo) { diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h index d369aeb..59155e9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h @@ -37,7 +37,7 @@ static struct { } __attribute__((aligned(32))) lock = {0, {0}}; template <> -INLINE atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr, +inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type val, memory_order mo) { DCHECK(mo & @@ -55,14 +55,14 @@ INLINE atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr, } template <> -INLINE atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr, +inline atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type val, memory_order mo) { return atomic_fetch_add(ptr, -val, mo); } template <> -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr, +inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type *cmp, atomic_uint64_t::Type xchg, memory_order mo) { @@ -87,7 +87,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr, } template <> -INLINE atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr, +inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); @@ -100,7 +100,7 @@ INLINE atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr, } template <> -INLINE void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v, +inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h index b8685a8..7580ac2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h @@ -17,12 +17,12 @@ namespace __sanitizer { -INLINE void proc_yield(int cnt) { +inline void proc_yield(int cnt) { __asm__ __volatile__("" ::: "memory"); } template<typename T> -INLINE typename T::Type atomic_load( +inline typename T::Type atomic_load( const volatile T *a, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_consume | memory_order_acquire | memory_order_seq_cst)); @@ -60,7 +60,7 @@ INLINE typename T::Type atomic_load( } template<typename T> -INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { +inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); DCHECK(!((uptr)a % sizeof(*a))); diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_x86.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_x86.h index f2ce553..51597b4 100644 --- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_x86.h +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_x86.h @@ -16,7 +16,7 @@ namespace __sanitizer { -INLINE void proc_yield(int cnt) { +inline void proc_yield(int cnt) { __asm__ __volatile__("" ::: "memory"); for (int i = 0; i < cnt; i++) __asm__ __volatile__("pause"); @@ -24,7 +24,7 @@ INLINE void proc_yield(int cnt) { } template<typename T> -INLINE typename T::Type atomic_load( +inline typename T::Type atomic_load( const volatile T *a, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_consume | memory_order_acquire | memory_order_seq_cst)); @@ -70,7 +70,7 @@ INLINE typename T::Type atomic_load( } template<typename T> -INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { +inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); DCHECK(!((uptr)a % sizeof(*a))); diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h index 6a7c546..31317ad 100644 --- a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h @@ -54,21 +54,21 @@ extern "C" long long _InterlockedExchangeAdd64(long long volatile *Addend, namespace __sanitizer { -INLINE void atomic_signal_fence(memory_order) { +inline void atomic_signal_fence(memory_order) { _ReadWriteBarrier(); } -INLINE void atomic_thread_fence(memory_order) { +inline void atomic_thread_fence(memory_order) { _mm_mfence(); } -INLINE void proc_yield(int cnt) { +inline void proc_yield(int cnt) { for (int i = 0; i < cnt; i++) _mm_pause(); } template<typename T> -INLINE typename T::Type atomic_load( +inline typename T::Type atomic_load( const volatile T *a, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_consume | memory_order_acquire | memory_order_seq_cst)); @@ -86,7 +86,7 @@ INLINE typename T::Type atomic_load( } template<typename T> -INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { +inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); DCHECK(!((uptr)a % sizeof(*a))); @@ -102,7 +102,7 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { atomic_thread_fence(memory_order_seq_cst); } -INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a, +inline u32 atomic_fetch_add(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -110,7 +110,7 @@ INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a, (long)v); } -INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, +inline uptr atomic_fetch_add(volatile atomic_uintptr_t *a, uptr v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -123,7 +123,7 @@ INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, #endif } -INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a, +inline u32 atomic_fetch_sub(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -131,7 +131,7 @@ INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a, -(long)v); } -INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, +inline uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, uptr v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -144,28 +144,28 @@ INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, #endif } -INLINE u8 atomic_exchange(volatile atomic_uint8_t *a, +inline u8 atomic_exchange(volatile atomic_uint8_t *a, u8 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); return (u8)_InterlockedExchange8((volatile char*)&a->val_dont_use, v); } -INLINE u16 atomic_exchange(volatile atomic_uint16_t *a, +inline u16 atomic_exchange(volatile atomic_uint16_t *a, u16 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); return (u16)_InterlockedExchange16((volatile short*)&a->val_dont_use, v); } -INLINE u32 atomic_exchange(volatile atomic_uint32_t *a, +inline u32 atomic_exchange(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); return (u32)_InterlockedExchange((volatile long*)&a->val_dont_use, v); } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a, u8 *cmp, u8 xchgv, memory_order mo) { @@ -191,7 +191,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a, return false; } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a, uptr *cmp, uptr xchg, memory_order mo) { @@ -204,7 +204,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a, return false; } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a, u16 *cmp, u16 xchg, memory_order mo) { @@ -217,7 +217,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a, return false; } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a, u32 *cmp, u32 xchg, memory_order mo) { @@ -230,7 +230,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a, return false; } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a, u64 *cmp, u64 xchg, memory_order mo) { @@ -244,7 +244,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a, } template<typename T> -INLINE bool atomic_compare_exchange_weak(volatile T *a, +inline bool atomic_compare_exchange_weak(volatile T *a, typename T::Type *cmp, typename T::Type xchg, memory_order mo) { diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h index ac16e0e..040db6f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.h +++ b/libsanitizer/sanitizer_common/sanitizer_common.h @@ -53,25 +53,25 @@ const u64 kExternalPCBit = 1ULL << 60; extern const char *SanitizerToolName; // Can be changed by the tool. extern atomic_uint32_t current_verbosity; -INLINE void SetVerbosity(int verbosity) { +inline void SetVerbosity(int verbosity) { atomic_store(¤t_verbosity, verbosity, memory_order_relaxed); } -INLINE int Verbosity() { +inline int Verbosity() { return atomic_load(¤t_verbosity, memory_order_relaxed); } #if SANITIZER_ANDROID -INLINE uptr GetPageSize() { +inline uptr GetPageSize() { // Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array. return 4096; } -INLINE uptr GetPageSizeCached() { +inline uptr GetPageSizeCached() { return 4096; } #else uptr GetPageSize(); extern uptr PageSizeCached; -INLINE uptr GetPageSizeCached() { +inline uptr GetPageSizeCached() { if (!PageSizeCached) PageSizeCached = GetPageSize(); return PageSizeCached; @@ -91,7 +91,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, // Memory management void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false); -INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) { +inline void *MmapOrDieQuietly(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type, /*raw_report*/ true); } void UnmapOrDie(void *addr, uptr size); @@ -121,6 +121,31 @@ bool MprotectReadOnly(uptr addr, uptr size); void MprotectMallocZones(void *addr, int prot); +#if SANITIZER_LINUX +// Unmap memory. Currently only used on Linux. +void UnmapFromTo(uptr from, uptr to); +#endif + +// Maps shadow_size_bytes of shadow memory and returns shadow address. It will +// be aligned to the mmap granularity * 2^shadow_scale, or to +// 2^min_shadow_base_alignment if that is larger. The returned address will +// have max(2^min_shadow_base_alignment, mmap granularity) on the left, and +// shadow_size_bytes bytes on the right, which on linux is mapped no access. +// The high_mem_end may be updated if the original shadow size doesn't fit. +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, uptr &high_mem_end); + +// Reserve memory range [beg, end]. If madvise_shadow is true then apply +// madvise (e.g. hugepages, core dumping) requested by options. +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name, + bool madvise_shadow = true); + +// Protect size bytes of memory starting at addr. Also try to protect +// several pages at the start of the address space as specified by +// zero_base_shadow_start, at most up to the size or zero_base_max_shadow_start. +void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start, + uptr zero_base_max_shadow_start); + // Find an available address space. uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, uptr *largest_gap_found, uptr *max_occupied_addr); @@ -349,7 +374,7 @@ unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); } #endif -INLINE uptr MostSignificantSetBitIndex(uptr x) { +inline uptr MostSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); unsigned long up; #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) @@ -366,7 +391,7 @@ INLINE uptr MostSignificantSetBitIndex(uptr x) { return up; } -INLINE uptr LeastSignificantSetBitIndex(uptr x) { +inline uptr LeastSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); unsigned long up; #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) @@ -383,11 +408,11 @@ INLINE uptr LeastSignificantSetBitIndex(uptr x) { return up; } -INLINE bool IsPowerOfTwo(uptr x) { +inline bool IsPowerOfTwo(uptr x) { return (x & (x - 1)) == 0; } -INLINE uptr RoundUpToPowerOfTwo(uptr size) { +inline uptr RoundUpToPowerOfTwo(uptr size) { CHECK(size); if (IsPowerOfTwo(size)) return size; @@ -397,20 +422,20 @@ INLINE uptr RoundUpToPowerOfTwo(uptr size) { return 1ULL << (up + 1); } -INLINE uptr RoundUpTo(uptr size, uptr boundary) { +inline uptr RoundUpTo(uptr size, uptr boundary) { RAW_CHECK(IsPowerOfTwo(boundary)); return (size + boundary - 1) & ~(boundary - 1); } -INLINE uptr RoundDownTo(uptr x, uptr boundary) { +inline uptr RoundDownTo(uptr x, uptr boundary) { return x & ~(boundary - 1); } -INLINE bool IsAligned(uptr a, uptr alignment) { +inline bool IsAligned(uptr a, uptr alignment) { return (a & (alignment - 1)) == 0; } -INLINE uptr Log2(uptr x) { +inline uptr Log2(uptr x) { CHECK(IsPowerOfTwo(x)); return LeastSignificantSetBitIndex(x); } @@ -426,14 +451,14 @@ template<class T> void Swap(T& a, T& b) { } // Char handling -INLINE bool IsSpace(int c) { +inline bool IsSpace(int c) { return (c == ' ') || (c == '\n') || (c == '\t') || (c == '\f') || (c == '\r') || (c == '\v'); } -INLINE bool IsDigit(int c) { +inline bool IsDigit(int c) { return (c >= '0') && (c <= '9'); } -INLINE int ToLower(int c) { +inline int ToLower(int c) { return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c; } @@ -649,7 +674,8 @@ enum ModuleArch { kModuleArchARMV7, kModuleArchARMV7S, kModuleArchARMV7K, - kModuleArchARM64 + kModuleArchARM64, + kModuleArchRISCV64 }; // Opens the file 'file_name" and reads up to 'max_len' bytes. @@ -693,6 +719,8 @@ inline const char *ModuleArchToString(ModuleArch arch) { return "armv7k"; case kModuleArchARM64: return "arm64"; + case kModuleArchRISCV64: + return "riscv64"; } CHECK(0 && "Invalid module arch"); return ""; @@ -815,15 +843,15 @@ void WriteToSyslog(const char *buffer); #if SANITIZER_MAC || SANITIZER_WIN_TRACE void LogFullErrorReport(const char *buffer); #else -INLINE void LogFullErrorReport(const char *buffer) {} +inline void LogFullErrorReport(const char *buffer) {} #endif #if SANITIZER_LINUX || SANITIZER_MAC void WriteOneLineToSyslog(const char *s); void LogMessageOnPrintf(const char *str); #else -INLINE void WriteOneLineToSyslog(const char *s) {} -INLINE void LogMessageOnPrintf(const char *str) {} +inline void WriteOneLineToSyslog(const char *s) {} +inline void LogMessageOnPrintf(const char *str) {} #endif #if SANITIZER_LINUX || SANITIZER_WIN_TRACE @@ -831,21 +859,21 @@ INLINE void LogMessageOnPrintf(const char *str) {} void AndroidLogInit(); void SetAbortMessage(const char *); #else -INLINE void AndroidLogInit() {} +inline void AndroidLogInit() {} // FIXME: MacOS implementation could use CRSetCrashLogMessage. -INLINE void SetAbortMessage(const char *) {} +inline void SetAbortMessage(const char *) {} #endif #if SANITIZER_ANDROID void SanitizerInitializeUnwinder(); AndroidApiLevel AndroidGetApiLevel(); #else -INLINE void AndroidLogWrite(const char *buffer_unused) {} -INLINE void SanitizerInitializeUnwinder() {} -INLINE AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; } +inline void AndroidLogWrite(const char *buffer_unused) {} +inline void SanitizerInitializeUnwinder() {} +inline AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; } #endif -INLINE uptr GetPthreadDestructorIterations() { +inline uptr GetPthreadDestructorIterations() { #if SANITIZER_ANDROID return (AndroidGetApiLevel() == ANDROID_LOLLIPOP_MR1) ? 8 : 4; #elif SANITIZER_POSIX @@ -951,7 +979,7 @@ RunOnDestruction<Fn> at_scope_exit(Fn fn) { #if SANITIZER_LINUX && SANITIZER_S390_64 void AvoidCVE_2016_2143(); #else -INLINE void AvoidCVE_2016_2143() {} +inline void AvoidCVE_2016_2143() {} #endif struct StackDepotStats { @@ -972,12 +1000,26 @@ bool GetRandom(void *buffer, uptr length, bool blocking = true); // Returns the number of logical processors on the system. u32 GetNumberOfCPUs(); extern u32 NumberOfCPUsCached; -INLINE u32 GetNumberOfCPUsCached() { +inline u32 GetNumberOfCPUsCached() { if (!NumberOfCPUsCached) NumberOfCPUsCached = GetNumberOfCPUs(); return NumberOfCPUsCached; } +template <typename T> +class ArrayRef { + public: + ArrayRef() {} + ArrayRef(T *begin, T *end) : begin_(begin), end_(end) {} + + T *begin() { return begin_; } + T *end() { return end_; } + + private: + T *begin_ = nullptr; + T *end_ = nullptr; +}; + } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc index 57f8b2d..5b51078 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc @@ -445,8 +445,10 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { c2 = (unsigned char)s2[i]; if (c1 != c2 || c1 == '\0') break; } - COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1); - COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1); + if (common_flags()->intercept_strcmp) { + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1); + } int result = CharCmpX(c1, c2); CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1, s2, result); @@ -2199,6 +2201,24 @@ INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) { #define INIT_CLOCK_GETTIME #endif +#if SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID +INTERCEPTOR(int, clock_getcpuclockid, pid_t pid, + __sanitizer_clockid_t *clockid) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, clock_getcpuclockid, pid, clockid); + int res = REAL(clock_getcpuclockid)(pid, clockid); + if (!res && clockid) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, clockid, sizeof *clockid); + } + return res; +} + +#define INIT_CLOCK_GETCPUCLOCKID \ + COMMON_INTERCEPT_FUNCTION(clock_getcpuclockid); +#else +#define INIT_CLOCK_GETCPUCLOCKID +#endif + #if SANITIZER_INTERCEPT_GETITIMER INTERCEPTOR(int, getitimer, int which, void *curr_value) { void *ctx; @@ -3092,6 +3112,34 @@ INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, #define INIT_SENDMMSG #endif +#if SANITIZER_INTERCEPT_SYSMSG +INTERCEPTOR(int, msgsnd, int msqid, const void *msgp, SIZE_T msgsz, + int msgflg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, msgsnd, msqid, msgp, msgsz, msgflg); + if (msgp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, msgp, sizeof(long) + msgsz); + int res = REAL(msgsnd)(msqid, msgp, msgsz, msgflg); + return res; +} + +INTERCEPTOR(SSIZE_T, msgrcv, int msqid, void *msgp, SIZE_T msgsz, + long msgtyp, int msgflg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, msgrcv, msqid, msgp, msgsz, msgtyp, msgflg); + SSIZE_T len = REAL(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg); + if (len != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msgp, sizeof(long) + len); + return len; +} + +#define INIT_SYSMSG \ + COMMON_INTERCEPT_FUNCTION(msgsnd); \ + COMMON_INTERCEPT_FUNCTION(msgrcv); +#else +#define INIT_SYSMSG +#endif + #if SANITIZER_INTERCEPT_GETPEERNAME INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) { void *ctx; @@ -4039,6 +4087,41 @@ INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) { #define INIT_SIGSETOPS #endif +#if SANITIZER_INTERCEPT_SIGSET_LOGICOPS +INTERCEPTOR(int, sigandset, __sanitizer_sigset_t *dst, + __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigandset, dst, src1, src2); + if (src1) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1)); + if (src2) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2)); + int res = REAL(sigandset)(dst, src1, src2); + if (!res && dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + return res; +} + +INTERCEPTOR(int, sigorset, __sanitizer_sigset_t *dst, + __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigorset, dst, src1, src2); + if (src1) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1)); + if (src2) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2)); + int res = REAL(sigorset)(dst, src1, src2); + if (!res && dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + return res; +} +#define INIT_SIGSET_LOGICOPS \ + COMMON_INTERCEPT_FUNCTION(sigandset); \ + COMMON_INTERCEPT_FUNCTION(sigorset); +#else +#define INIT_SIGSET_LOGICOPS +#endif + #if SANITIZER_INTERCEPT_SIGPENDING INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) { void *ctx; @@ -4792,6 +4875,34 @@ INTERCEPTOR(char *, tmpnam_r, char *s) { #define INIT_TMPNAM_R #endif +#if SANITIZER_INTERCEPT_PTSNAME +INTERCEPTOR(char *, ptsname, int fd) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ptsname, fd); + char *res = REAL(ptsname)(fd); + if (res != nullptr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); + return res; +} +#define INIT_PTSNAME COMMON_INTERCEPT_FUNCTION(ptsname); +#else +#define INIT_PTSNAME +#endif + +#if SANITIZER_INTERCEPT_PTSNAME_R +INTERCEPTOR(int, ptsname_r, int fd, char *name, SIZE_T namesize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ptsname_r, fd, name, namesize); + int res = REAL(ptsname_r)(fd, name, namesize); + if (res == 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, REAL(strlen)(name) + 1); + return res; +} +#define INIT_PTSNAME_R COMMON_INTERCEPT_FUNCTION(ptsname_r); +#else +#define INIT_PTSNAME_R +#endif + #if SANITIZER_INTERCEPT_TTYNAME INTERCEPTOR(char *, ttyname, int fd) { void *ctx; @@ -5763,6 +5874,79 @@ INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p, #define INIT_XDR #endif // SANITIZER_INTERCEPT_XDR +#if SANITIZER_INTERCEPT_XDRREC +typedef int (*xdrrec_cb)(char*, char*, int); +struct XdrRecWrapper { + char *handle; + xdrrec_cb rd, wr; +}; +typedef AddrHashMap<XdrRecWrapper *, 11> XdrRecWrapMap; +static XdrRecWrapMap *xdrrec_wrap_map; + +static int xdrrec_wr_wrap(char *handle, char *buf, int count) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(buf, count); + XdrRecWrapper *wrap = (XdrRecWrapper *)handle; + return wrap->wr(wrap->handle, buf, count); +} + +static int xdrrec_rd_wrap(char *handle, char *buf, int count) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + XdrRecWrapper *wrap = (XdrRecWrapper *)handle; + return wrap->rd(wrap->handle, buf, count); +} + +// This doesn't apply to the solaris version as it has a different function +// signature. +INTERCEPTOR(void, xdrrec_create, __sanitizer_XDR *xdr, unsigned sndsize, + unsigned rcvsize, char *handle, int (*rd)(char*, char*, int), + int (*wr)(char*, char*, int)) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdrrec_create, xdr, sndsize, rcvsize, + handle, rd, wr); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &xdr->x_op, sizeof xdr->x_op); + + // We can't allocate a wrapper on the stack, as the handle is used outside + // this stack frame. So we put it on the heap, and keep track of it with + // the HashMap (keyed by x_private). When we later need to xdr_destroy, + // we can index the map, free the wrapper, and then clean the map entry. + XdrRecWrapper *wrap_data = + (XdrRecWrapper *)InternalAlloc(sizeof(XdrRecWrapper)); + wrap_data->handle = handle; + wrap_data->rd = rd; + wrap_data->wr = wr; + if (wr) + wr = xdrrec_wr_wrap; + if (rd) + rd = xdrrec_rd_wrap; + handle = (char *)wrap_data; + + REAL(xdrrec_create)(xdr, sndsize, rcvsize, handle, rd, wr); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdr, sizeof *xdr); + + XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, false, true); + *wrap = wrap_data; +} + +// We have to intercept this to be able to free wrapper memory; +// otherwise it's not necessary. +INTERCEPTOR(void, xdr_destroy, __sanitizer_XDR *xdr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdr_destroy, xdr); + + XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, true); + InternalFree(*wrap); + REAL(xdr_destroy)(xdr); +} +#define INIT_XDRREC_LINUX \ + static u64 xdrrec_wrap_mem[sizeof(XdrRecWrapMap) / sizeof(u64) + 1]; \ + xdrrec_wrap_map = new ((void *)&xdrrec_wrap_mem) XdrRecWrapMap(); \ + COMMON_INTERCEPT_FUNCTION(xdrrec_create); \ + COMMON_INTERCEPT_FUNCTION(xdr_destroy); +#else +#define INIT_XDRREC_LINUX +#endif + #if SANITIZER_INTERCEPT_TSEARCH INTERCEPTOR(void *, tsearch, void *key, void **rootp, int (*compar)(const void *, const void *)) { @@ -7271,23 +7455,26 @@ INTERCEPTOR(int, setttyentpath, char *path) { #endif #if SANITIZER_INTERCEPT_PROTOENT -INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, getprotoent); - struct __sanitizer_protoent *p = REAL(getprotoent)(); - if (p) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); +static void write_protoent(void *ctx, struct __sanitizer_protoent *p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); - SIZE_T pp_size = 1; // One handles the trailing \0 + SIZE_T pp_size = 1; // One handles the trailing \0 - for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); + for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, - pp_size * sizeof(char **)); - } + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, + pp_size * sizeof(char **)); +} + +INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotoent); + struct __sanitizer_protoent *p = REAL(getprotoent)(); + if (p) + write_protoent(ctx, p); return p; } @@ -7297,19 +7484,8 @@ INTERCEPTOR(struct __sanitizer_protoent *, getprotobyname, const char *name) { if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); struct __sanitizer_protoent *p = REAL(getprotobyname)(name); - if (p) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); - - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); - - SIZE_T pp_size = 1; // One handles the trailing \0 - - for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); - - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, - pp_size * sizeof(char **)); - } + if (p) + write_protoent(ctx, p); return p; } @@ -7317,19 +7493,8 @@ INTERCEPTOR(struct __sanitizer_protoent *, getprotobynumber, int proto) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber, proto); struct __sanitizer_protoent *p = REAL(getprotobynumber)(proto); - if (p) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); - - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); - - SIZE_T pp_size = 1; // One handles the trailing \0 - - for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); - - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, - pp_size * sizeof(char **)); - } + if (p) + write_protoent(ctx, p); return p; } #define INIT_PROTOENT \ @@ -7340,6 +7505,58 @@ INTERCEPTOR(struct __sanitizer_protoent *, getprotobynumber, int proto) { #define INIT_PROTOENT #endif +#if SANITIZER_INTERCEPT_PROTOENT_R +INTERCEPTOR(int, getprotoent_r, struct __sanitizer_protoent *result_buf, + char *buf, SIZE_T buflen, struct __sanitizer_protoent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotoent_r, result_buf, buf, buflen, + result); + int res = REAL(getprotoent_r)(result_buf, buf, buflen, result); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); + if (!res && *result) + write_protoent(ctx, *result); + return res; +} + +INTERCEPTOR(int, getprotobyname_r, const char *name, + struct __sanitizer_protoent *result_buf, char *buf, SIZE_T buflen, + struct __sanitizer_protoent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotobyname_r, name, result_buf, buf, + buflen, result); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); + int res = REAL(getprotobyname_r)(name, result_buf, buf, buflen, result); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); + if (!res && *result) + write_protoent(ctx, *result); + return res; +} + +INTERCEPTOR(int, getprotobynumber_r, int num, + struct __sanitizer_protoent *result_buf, char *buf, + SIZE_T buflen, struct __sanitizer_protoent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber_r, num, result_buf, buf, + buflen, result); + int res = REAL(getprotobynumber_r)(num, result_buf, buf, buflen, result); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); + if (!res && *result) + write_protoent(ctx, *result); + return res; +} + +#define INIT_PROTOENT_R \ + COMMON_INTERCEPT_FUNCTION(getprotoent_r); \ + COMMON_INTERCEPT_FUNCTION(getprotobyname_r); \ + COMMON_INTERCEPT_FUNCTION(getprotobynumber_r); +#else +#define INIT_PROTOENT_R +#endif + #if SANITIZER_INTERCEPT_NETENT INTERCEPTOR(struct __sanitizer_netent *, getnetent) { void *ctx; @@ -9676,12 +9893,25 @@ INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size, } } qsort_compar_f old_compar = qsort_compar; - qsort_compar = compar; SIZE_T old_size = qsort_size; - qsort_size = size; + // Handle qsort() implementations that recurse using an + // interposable function call: + bool already_wrapped = compar == wrapped_qsort_compar; + if (already_wrapped) { + // This case should only happen if the qsort() implementation calls itself + // using a preemptible function call (e.g. the FreeBSD libc version). + // Check that the size and comparator arguments are as expected. + CHECK_NE(compar, qsort_compar); + CHECK_EQ(qsort_size, size); + } else { + qsort_compar = compar; + qsort_size = size; + } REAL(qsort)(base, nmemb, size, wrapped_qsort_compar); - qsort_compar = old_compar; - qsort_size = old_size; + if (!already_wrapped) { + qsort_compar = old_compar; + qsort_size = old_size; + } COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); } #define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort) @@ -9714,12 +9944,25 @@ INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size, } } qsort_r_compar_f old_compar = qsort_r_compar; - qsort_r_compar = compar; SIZE_T old_size = qsort_r_size; - qsort_r_size = size; + // Handle qsort_r() implementations that recurse using an + // interposable function call: + bool already_wrapped = compar == wrapped_qsort_r_compar; + if (already_wrapped) { + // This case should only happen if the qsort() implementation calls itself + // using a preemptible function call (e.g. the FreeBSD libc version). + // Check that the size and comparator arguments are as expected. + CHECK_NE(compar, qsort_r_compar); + CHECK_EQ(qsort_r_size, size); + } else { + qsort_r_compar = compar; + qsort_r_size = size; + } REAL(qsort_r)(base, nmemb, size, wrapped_qsort_r_compar, arg); - qsort_r_compar = old_compar; - qsort_r_size = old_size; + if (!already_wrapped) { + qsort_r_compar = old_compar; + qsort_r_size = old_size; + } COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); } #define INIT_QSORT_R COMMON_INTERCEPT_FUNCTION(qsort_r) @@ -9853,6 +10096,7 @@ static void InitializeCommonInterceptors() { INIT_FGETGRENT_R; INIT_SETPWENT; INIT_CLOCK_GETTIME; + INIT_CLOCK_GETCPUCLOCKID; INIT_GETITIMER; INIT_TIME; INIT_GLOB; @@ -9879,6 +10123,7 @@ static void InitializeCommonInterceptors() { INIT_SENDMSG; INIT_RECVMMSG; INIT_SENDMMSG; + INIT_SYSMSG; INIT_GETPEERNAME; INIT_IOCTL; INIT_INET_ATON; @@ -9915,6 +10160,7 @@ static void InitializeCommonInterceptors() { INIT_SIGWAITINFO; INIT_SIGTIMEDWAIT; INIT_SIGSETOPS; + INIT_SIGSET_LOGICOPS; INIT_SIGPENDING; INIT_SIGPROCMASK; INIT_PTHREAD_SIGMASK; @@ -9956,6 +10202,8 @@ static void InitializeCommonInterceptors() { INIT_PTHREAD_BARRIERATTR_GETPSHARED; INIT_TMPNAM; INIT_TMPNAM_R; + INIT_PTSNAME; + INIT_PTSNAME_R; INIT_TTYNAME; INIT_TTYNAME_R; INIT_TEMPNAM; @@ -9985,6 +10233,7 @@ static void InitializeCommonInterceptors() { INIT_BZERO; INIT_FTIME; INIT_XDR; + INIT_XDRREC_LINUX; INIT_TSEARCH; INIT_LIBIO_INTERNALS; INIT_FOPEN; @@ -10042,6 +10291,7 @@ static void InitializeCommonInterceptors() { INIT_STRMODE; INIT_TTYENT; INIT_PROTOENT; + INIT_PROTOENT_R; INIT_NETENT; INIT_GETMNTINFO; INIT_MI_VECTOR_HASH; diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc index bbbedda..082398b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc @@ -340,6 +340,12 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc, size = 0; } COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size); + // For %ms/%mc, write the allocated output buffer as well. + if (dir.allocate) { + char *buf = *(char **)argp; + if (buf) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1); + } } } diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S new file mode 100644 index 0000000..b7ec278 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S @@ -0,0 +1,56 @@ +#if (defined(__riscv) && (__riscv_xlen == 64)) && defined(__linux__) + +#include "sanitizer_common/sanitizer_asm.h" + +ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA) + +.comm _ZN14__interception10real_vforkE,8,8 +.globl ASM_WRAPPER_NAME(vfork) +ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork)) +ASM_WRAPPER_NAME(vfork): + // Save ra in the off-stack spill area. + // allocate space on stack + addi sp, sp, -16 + // store ra value + sd ra, 8(sp) + call COMMON_INTERCEPTOR_SPILL_AREA + // restore previous values from stack + ld ra, 8(sp) + // adjust stack + addi sp, sp, 16 + // store ra by x10 + sd ra, 0(x10) + + // Call real vfork. This may return twice. User code that runs between the first and the second return + // may clobber the stack frame of the interceptor; that's why it does not have a frame. + la x10, _ZN14__interception10real_vforkE + ld x10, 0(x10) + jalr x10 + + // adjust stack + addi sp, sp, -16 + // store x10 by adjusted stack + sd x10, 8(sp) + // jump to exit label if x10 is 0 + beqz x10, .L_exit + + // x0 != 0 => parent process. Clear stack shadow. + // put old sp to x10 + addi x10, sp, 16 + call COMMON_INTERCEPTOR_HANDLE_VFORK + +.L_exit: + // Restore ra + call COMMON_INTERCEPTOR_SPILL_AREA + ld ra, 0(x10) + // load value by stack + ld x10, 8(sp) + // adjust stack + addi sp, sp, 16 + ret +ASM_SIZE(vfork) + +.weak vfork +.set vfork, ASM_WRAPPER_NAME(vfork) + +#endif diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp index 0c918eb..047c5a1 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp @@ -139,6 +139,59 @@ uptr ReservedAddressRange::InitAligned(uptr size, uptr align, return start; } +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS + +// Reserve memory range [beg, end]. +// We need to use inclusive range because end+1 may not be representable. +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name, + bool madvise_shadow) { + CHECK_EQ((beg % GetMmapGranularity()), 0); + CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); + uptr size = end - beg + 1; + DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. + if (madvise_shadow ? !MmapFixedSuperNoReserve(beg, size, name) + : !MmapFixedNoReserve(beg, size, name)) { + Report( + "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " + "Perhaps you're using ulimit -v\n", + size); + Abort(); + } + if (madvise_shadow && common_flags()->use_madv_dontdump) + DontDumpShadowMemory(beg, size); +} + +void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start, + uptr zero_base_max_shadow_start) { + if (!size) + return; + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) + return; + // A few pages at the start of the address space can not be protected. + // But we really want to protect as much as possible, to prevent this memory + // being returned as a result of a non-FIXED mmap(). + if (addr == zero_base_shadow_start) { + uptr step = GetMmapGranularity(); + while (size > step && addr < zero_base_max_shadow_start) { + addr += step; + size -= step; + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) + return; + } + } + + Report( + "ERROR: Failed to protect the shadow gap. " + "%s cannot proceed correctly. ABORTING.\n", + SanitizerToolName); + DumpProcessMap(); + Die(); +} + +#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS + } // namespace __sanitizer SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify, diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc index 532ac9e..1b89d6e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc @@ -2294,9 +2294,10 @@ PRE_SYSCALL(ni_syscall)() {} POST_SYSCALL(ni_syscall)(long res) {} PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { -#if !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__)) +#if !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ + SANITIZER_RISCV64) if (data) { if (request == ptrace_setregs) { PRE_READ((void *)data, struct_user_regs_struct_sz); @@ -2315,9 +2316,10 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { } POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) { -#if !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__)) +#if !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ + SANITIZER_RISCV64) if (res >= 0 && data) { // Note that this is different from the interceptor in // sanitizer_common_interceptors.inc. diff --git a/libsanitizer/sanitizer_common/sanitizer_errno_codes.h b/libsanitizer/sanitizer_common/sanitizer_errno_codes.h index f388d0d..192e939 100644 --- a/libsanitizer/sanitizer_common/sanitizer_errno_codes.h +++ b/libsanitizer/sanitizer_common/sanitizer_errno_codes.h @@ -24,6 +24,7 @@ namespace __sanitizer { #define errno_ENOMEM 12 #define errno_EBUSY 16 #define errno_EINVAL 22 +#define errno_ENAMETOOLONG 36 // Those might not present or their value differ on different platforms. extern const int errno_EOWNERDEAD; diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp index 684ee1e..d329049 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp @@ -91,7 +91,7 @@ class FlagHandlerInclude : public FlagHandlerBase { } return parser_->ParseFile(value, ignore_missing_); } - bool Format(char *buffer, uptr size) { + bool Format(char *buffer, uptr size) override { // Note `original_path_` isn't actually what's parsed due to `%` // substitutions. Printing the substituted path would require holding onto // mmap'ed memory. diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc index 065258a..d141247 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flags.inc +++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc @@ -40,7 +40,12 @@ COMMON_FLAG(bool, fast_unwind_on_check, false, COMMON_FLAG(bool, fast_unwind_on_fatal, false, "If available, use the fast frame-pointer-based unwinder on fatal " "errors.") -COMMON_FLAG(bool, fast_unwind_on_malloc, true, +// ARM thumb/thumb2 frame pointer is inconsistent on GCC and Clang [1] +// and fast-unwider is also unreliable with mixing arm and thumb code [2]. +// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92172 +// [2] https://bugs.llvm.org/show_bug.cgi?id=44158 +COMMON_FLAG(bool, fast_unwind_on_malloc, + !(SANITIZER_LINUX && !SANITIZER_ANDROID && SANITIZER_ARM), "If available, use the fast frame-pointer-based unwinder on " "malloc/free.") COMMON_FLAG(bool, handle_ioctl, false, "Intercept and handle ioctl requests.") @@ -195,6 +200,9 @@ COMMON_FLAG(bool, intercept_strtok, true, COMMON_FLAG(bool, intercept_strpbrk, true, "If set, uses custom wrappers for strpbrk function " "to find more errors.") +COMMON_FLAG( + bool, intercept_strcmp, true, + "If set, uses custom wrappers for strcmp functions to find more errors.") COMMON_FLAG(bool, intercept_strlen, true, "If set, uses custom wrappers for strlen and strnlen functions " "to find more errors.") diff --git a/libsanitizer/sanitizer_common/sanitizer_getauxval.h b/libsanitizer/sanitizer_common/sanitizer_getauxval.h index 86ad3a5..38439e4 100644 --- a/libsanitizer/sanitizer_common/sanitizer_getauxval.h +++ b/libsanitizer/sanitizer_common/sanitizer_getauxval.h @@ -21,8 +21,9 @@ #if SANITIZER_LINUX || SANITIZER_FUCHSIA -# if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \ - SANITIZER_FUCHSIA +# if (__GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \ + SANITIZER_FUCHSIA) && \ + !SANITIZER_GO # define SANITIZER_USE_GETAUXVAL 1 # else # define SANITIZER_USE_GETAUXVAL 0 diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h index d0ffc79..a6c5514 100644 --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h @@ -196,9 +196,6 @@ typedef u64 tid_t; // This header should NOT include any other headers to avoid portability issues. // Common defs. -#ifndef INLINE -#define INLINE inline -#endif #define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE #define SANITIZER_WEAK_DEFAULT_IMPL \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE @@ -333,14 +330,10 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond, #define UNIMPLEMENTED() UNREACHABLE("unimplemented") -#define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__) +#define COMPILER_CHECK(pred) static_assert(pred, "") #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) -#define IMPL_PASTE(a, b) a##b -#define IMPL_COMPILER_ASSERT(pred, line) \ - typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1] - // Limits for integral types. We have to redefine it in case we don't // have stdint.h (like in Visual Studio 9). #undef __INT64_C diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp index 11c03e2..c84946c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp @@ -154,6 +154,8 @@ namespace __sanitizer { #if SANITIZER_LINUX && defined(__x86_64__) #include "sanitizer_syscall_linux_x86_64.inc" +#elif SANITIZER_LINUX && SANITIZER_RISCV64 +#include "sanitizer_syscall_linux_riscv64.inc" #elif SANITIZER_LINUX && defined(__aarch64__) #include "sanitizer_syscall_linux_aarch64.inc" #elif SANITIZER_LINUX && defined(__arm__) @@ -187,6 +189,10 @@ uptr internal_munmap(void *addr, uptr length) { int internal_mprotect(void *addr, uptr length, int prot) { return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); } + +int internal_madvise(uptr addr, uptr length, int advice) { + return internal_syscall(SYSCALL(madvise), addr, length, advice); +} #endif uptr internal_close(fd_t fd) { @@ -422,15 +428,6 @@ uptr internal_sched_yield() { return internal_syscall(SYSCALL(sched_yield)); } -void internal__exit(int exitcode) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD - internal_syscall(SYSCALL(exit), exitcode); -#else - internal_syscall(SYSCALL(exit_group), exitcode); -#endif - Die(); // Unreachable. -} - unsigned int internal_sleep(unsigned int seconds) { struct timespec ts; ts.tv_sec = seconds; @@ -447,6 +444,17 @@ uptr internal_execve(const char *filename, char *const argv[], } #endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if !SANITIZER_NETBSD +void internal__exit(int exitcode) { +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS + internal_syscall(SYSCALL(exit), exitcode); +#else + internal_syscall(SYSCALL(exit_group), exitcode); +#endif + Die(); // Unreachable. +} +#endif // !SANITIZER_NETBSD + // ----------------- sanitizer_common.h bool FileExists(const char *filename) { if (ShouldMockFailureToOpen(filename)) @@ -706,7 +714,7 @@ struct linux_dirent { }; #else struct linux_dirent { -#if SANITIZER_X32 || defined(__aarch64__) +#if SANITIZER_X32 || defined(__aarch64__) || SANITIZER_RISCV64 u64 d_ino; u64 d_off; #else @@ -714,7 +722,7 @@ struct linux_dirent { unsigned long d_off; #endif unsigned short d_reclen; -#ifdef __aarch64__ +#if defined(__aarch64__) || SANITIZER_RISCV64 unsigned char d_type; #endif char d_name[256]; @@ -796,11 +804,29 @@ int internal_sysctl(const int *name, unsigned int namelen, void *oldp, #if SANITIZER_FREEBSD int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, const void *newp, uptr newlen) { - static decltype(sysctlbyname) *real = nullptr; - if (!real) - real = (decltype(sysctlbyname) *)dlsym(RTLD_NEXT, "sysctlbyname"); - CHECK(real); - return real(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen); + // Note: this function can be called during startup, so we need to avoid + // calling any interceptable functions. On FreeBSD >= 1300045 sysctlbyname() + // is a real syscall, but for older versions it calls sysctlnametomib() + // followed by sysctl(). To avoid calling the intercepted version and + // asserting if this happens during startup, call the real sysctlnametomib() + // followed by internal_sysctl() if the syscall is not available. +#ifdef SYS___sysctlbyname + return internal_syscall(SYSCALL(__sysctlbyname), sname, + internal_strlen(sname), oldp, (size_t *)oldlenp, newp, + (size_t)newlen); +#else + static decltype(sysctlnametomib) *real_sysctlnametomib = nullptr; + if (!real_sysctlnametomib) + real_sysctlnametomib = + (decltype(sysctlnametomib) *)dlsym(RTLD_NEXT, "sysctlnametomib"); + CHECK(real_sysctlnametomib); + + int oid[CTL_MAXNAME]; + size_t len = CTL_MAXNAME; + if (real_sysctlnametomib(sname, oid, &len) == -1) + return (-1); + return internal_sysctl(oid, len, oldp, oldlenp, newp, newlen); +#endif } #endif #endif @@ -861,9 +887,8 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; - return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, - (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0], - sizeof(__sanitizer_kernel_sigset_t)); + return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set, + (uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t)); #endif } @@ -1046,6 +1071,8 @@ uptr GetMaxVirtualAddress() { // This should (does) work for both PowerPC64 Endian modes. // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; +#elif SANITIZER_RISCV64 + return (1ULL << 38) - 1; # elif defined(__mips64) return (1ULL << 40) - 1; // 0x000000ffffffffffUL; # elif defined(__s390x__) @@ -1340,6 +1367,55 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, : "memory", "$29" ); return res; } +#elif SANITIZER_RISCV64 +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; + + register int (*__fn)(void *) __asm__("a0") = fn; + register void *__stack __asm__("a1") = child_stack; + register int __flags __asm__("a2") = flags; + register void *__arg __asm__("a3") = arg; + register int *__ptid __asm__("a4") = parent_tidptr; + register void *__tls __asm__("a5") = newtls; + register int *__ctid __asm__("a6") = child_tidptr; + + __asm__ __volatile__( + "mv a0,a2\n" /* flags */ + "mv a2,a4\n" /* ptid */ + "mv a3,a5\n" /* tls */ + "mv a4,a6\n" /* ctid */ + "addi a7, zero, %9\n" /* clone */ + + "ecall\n" + + /* if (%r0 != 0) + * return %r0; + */ + "bnez a0, 1f\n" + + /* In the child, now. Call "fn(arg)". */ + "ld a0, 8(sp)\n" + "ld a1, 16(sp)\n" + "jalr a1\n" + + /* Call _exit(%r0). */ + "addi a7, zero, %10\n" + "ecall\n" + "1:\n" + + : "=r"(res) + : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit) + : "ra", "memory"); + return res; +} #elif defined(__aarch64__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { @@ -2211,7 +2287,7 @@ void CheckNoDeepBind(const char *filename, int flag) { if (flag & RTLD_DEEPBIND) { Report( "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag" - " which is incompatibe with sanitizer runtime " + " which is incompatible with sanitizer runtime " "(see https://github.com/google/sanitizers/issues/611 for details" "). If you want to run %s library under sanitizers please remove " "RTLD_DEEPBIND from dlopen flags.\n", diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h index c162d1c..a8625ca 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux.h +++ b/libsanitizer/sanitizer_common/sanitizer_linux.h @@ -60,9 +60,9 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5); // internal_sigaction instead. int internal_sigaction_norestorer(int signum, const void *act, void *oldact); void internal_sigdelset(__sanitizer_sigset_t *set, int signum); -#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \ - || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) \ - || defined(__arm__) +#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \ + defined(__arm__) || SANITIZER_RISCV64 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif @@ -109,7 +109,7 @@ void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)); // Releases memory pages entirely within the [beg, end] address range. // The pages no longer count toward RSS; reads are guaranteed to return 0. // Requires (but does not verify!) that pages are MAP_PRIVATE. -INLINE void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) { +inline void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) { // man madvise on Linux promises zero-fill for anonymous private pages. // Testing shows the same behaviour for private (but not anonymous) mappings // of shm_open() files, as long as the underlying file is untouched. diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp index 0a54902..b8b9993 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -13,7 +13,7 @@ #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ SANITIZER_OPENBSD || SANITIZER_SOLARIS #include "sanitizer_allocator_internal.h" @@ -28,6 +28,10 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" +#if SANITIZER_NETBSD +#define _RTLD_SOURCE // for __lwp_gettcb_fast() / __lwp_getprivate_fast() +#endif + #include <dlfcn.h> // for dlsym() #include <link.h> #include <pthread.h> @@ -149,7 +153,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); my_pthread_attr_getstack(&attr, &stackaddr, &stacksize); pthread_attr_destroy(&attr); -#endif // SANITIZER_SOLARIS +#endif // SANITIZER_SOLARIS *stack_top = (uptr)stackaddr + stacksize; *stack_bottom = (uptr)stackaddr; @@ -189,20 +193,20 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor, #endif } -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \ +#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \ !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_SOLARIS static uptr g_tls_size; #ifdef __i386__ -# define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27)) +#define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27)) #else -# define CHECK_GET_TLS_STATIC_INFO_VERSION 0 +#define CHECK_GET_TLS_STATIC_INFO_VERSION 0 #endif #if CHECK_GET_TLS_STATIC_INFO_VERSION -# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) +#define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) #else -# define DL_INTERNAL_FUNCTION +#define DL_INTERNAL_FUNCTION #endif namespace { @@ -262,12 +266,11 @@ void InitTlsSize() { } #else void InitTlsSize() { } -#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && - // !SANITIZER_NETBSD && !SANITIZER_SOLARIS +#endif -#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \ - defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \ - defined(__arm__)) && \ +#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \ + defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \ + defined(__arm__) || SANITIZER_RISCV64) && \ SANITIZER_LINUX && !SANITIZER_ANDROID // sizeof(struct pthread) from glibc. static atomic_uintptr_t thread_descriptor_size; @@ -307,6 +310,21 @@ uptr ThreadDescriptorSize() { #elif defined(__mips__) // TODO(sagarthakur): add more values as per different glibc versions. val = FIRST_32_SECOND_64(1152, 1776); +#elif SANITIZER_RISCV64 + int major; + int minor; + int patch; + if (GetLibcVersion(&major, &minor, &patch) && major == 2) { + // TODO: consider adding an optional runtime check for an unknown (untested) + // glibc version + if (minor <= 28) // WARNING: the highest tested version is 2.29 + val = 1772; // no guarantees for this one + else if (minor <= 31) + val = 1772; // tested against glibc 2.29, 2.31 + else + val = 1936; // tested against glibc 2.32 + } + #elif defined(__aarch64__) // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22. val = 1776; @@ -327,15 +345,17 @@ uptr ThreadSelfOffset() { return kThreadSelfOffset; } -#if defined(__mips__) || defined(__powerpc64__) +#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 // TlsPreTcbSize includes size of struct pthread_descr and size of tcb // head structure. It lies before the static tls blocks. static uptr TlsPreTcbSize() { -# if defined(__mips__) +#if defined(__mips__) const uptr kTcbHead = 16; // sizeof (tcbhead_t) -# elif defined(__powerpc64__) +#elif defined(__powerpc64__) const uptr kTcbHead = 88; // sizeof (tcbhead_t) -# endif +#elif SANITIZER_RISCV64 + const uptr kTcbHead = 16; // sizeof (tcbhead_t) +#endif const uptr kTlsAlign = 16; const uptr kTlsPreTcbSize = RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign); @@ -345,11 +365,11 @@ static uptr TlsPreTcbSize() { uptr ThreadSelf() { uptr descr_addr; -# if defined(__i386__) +#if defined(__i386__) asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); -# elif defined(__x86_64__) +#elif defined(__x86_64__) asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); -# elif defined(__mips__) +#elif defined(__mips__) // MIPS uses TLS variant I. The thread pointer (in hardware register $29) // points to the end of the TCB + 0x7000. The pthread_descr structure is // immediately in front of the TCB. TlsPreTcbSize() includes the size of the @@ -361,12 +381,19 @@ uptr ThreadSelf() { rdhwr %0,$29;\ .set pop" : "=r" (thread_pointer)); descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); -# elif defined(__aarch64__) || defined(__arm__) +#elif defined(__aarch64__) || defined(__arm__) descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) - ThreadDescriptorSize(); -# elif defined(__s390__) +#elif SANITIZER_RISCV64 + uptr tcb_end; + asm volatile("mv %0, tp;\n" : "=r"(tcb_end)); + // https://github.com/riscv/riscv-elf-psabi-doc/issues/53 + const uptr kTlsTcbOffset = 0x800; + descr_addr = + reinterpret_cast<uptr>(tcb_end - kTlsTcbOffset - TlsPreTcbSize()); +#elif defined(__s390__) descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()); -# elif defined(__powerpc64__) +#elif defined(__powerpc64__) // PPC64LE uses TLS variant I. The thread pointer (in GPR 13) // points to the end of the TCB + 0x7000. The pthread_descr structure is // immediately in front of the TCB. TlsPreTcbSize() includes the size of the @@ -375,9 +402,9 @@ uptr ThreadSelf() { uptr thread_pointer; asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset)); descr_addr = thread_pointer - TlsPreTcbSize(); -# else -# error "unsupported CPU arch" -# endif +#else +#error "unsupported CPU arch" +#endif return descr_addr; } #endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX @@ -385,15 +412,15 @@ uptr ThreadSelf() { #if SANITIZER_FREEBSD static void **ThreadSelfSegbase() { void **segbase = 0; -# if defined(__i386__) +#if defined(__i386__) // sysarch(I386_GET_GSBASE, segbase); __asm __volatile("mov %%gs:0, %0" : "=r" (segbase)); -# elif defined(__x86_64__) +#elif defined(__x86_64__) // sysarch(AMD64_GET_FSBASE, segbase); __asm __volatile("movq %%fs:0, %0" : "=r" (segbase)); -# else -# error "unsupported CPU arch" -# endif +#else +#error "unsupported CPU arch" +#endif return segbase; } @@ -404,7 +431,13 @@ uptr ThreadSelf() { #if SANITIZER_NETBSD static struct tls_tcb * ThreadSelfTlsTcb() { - return (struct tls_tcb *)_lwp_getprivate(); + struct tls_tcb *tcb = nullptr; +#ifdef __HAVE___LWP_GETTCB_FAST + tcb = (struct tls_tcb *)__lwp_gettcb_fast(); +#elif defined(__HAVE___LWP_GETPRIVATE_FAST) + tcb = (struct tls_tcb *)__lwp_getprivate_fast(); +#endif + return tcb; } uptr ThreadSelf() { @@ -428,19 +461,19 @@ int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) { #if !SANITIZER_GO static void GetTls(uptr *addr, uptr *size) { #if SANITIZER_LINUX && !SANITIZER_ANDROID -# if defined(__x86_64__) || defined(__i386__) || defined(__s390__) +#if defined(__x86_64__) || defined(__i386__) || defined(__s390__) *addr = ThreadSelf(); *size = GetTlsSize(); *addr -= *size; *addr += ThreadDescriptorSize(); -# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \ - || defined(__arm__) +#elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \ + defined(__arm__) || SANITIZER_RISCV64 *addr = ThreadSelf(); *size = GetTlsSize(); -# else +#else *addr = 0; *size = 0; -# endif +#endif #elif SANITIZER_FREEBSD void** segbase = ThreadSelfSegbase(); *addr = 0; @@ -479,19 +512,19 @@ static void GetTls(uptr *addr, uptr *size) { *addr = 0; *size = 0; #else -# error "Unknown OS" +#error "Unknown OS" #endif } #endif #if !SANITIZER_GO uptr GetTlsSize() { -#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \ +#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \ SANITIZER_OPENBSD || SANITIZER_SOLARIS uptr addr, size; GetTls(&addr, &size); return size; -#elif defined(__mips__) || defined(__powerpc64__) +#elif defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16); #else return g_tls_size; @@ -526,11 +559,11 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, #if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD typedef ElfW(Phdr) Elf_Phdr; -#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 +#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 #define Elf_Phdr XElf32_Phdr #define dl_phdr_info xdl_phdr_info #define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) -#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD +#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD struct DlIteratePhdrData { InternalMmapVectorNoCtor<LoadedModule> *modules; @@ -697,19 +730,15 @@ u32 GetNumberOfCPUs() { #elif SANITIZER_SOLARIS return sysconf(_SC_NPROCESSORS_ONLN); #else -#if defined(CPU_COUNT) cpu_set_t CPUs; CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); return CPU_COUNT(&CPUs); -#else - return 1; -#endif #endif } #if SANITIZER_LINUX -# if SANITIZER_ANDROID +#if SANITIZER_ANDROID static atomic_uint8_t android_log_initialized; void AndroidLogInit() { @@ -753,7 +782,7 @@ void SetAbortMessage(const char *str) { if (&android_set_abort_message) android_set_abort_message(str); } -# else +#else void AndroidLogInit() {} static bool ShouldLogAfterPrintf() { return true; } @@ -761,7 +790,7 @@ static bool ShouldLogAfterPrintf() { return true; } void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); } void SetAbortMessage(const char *str) {} -# endif // SANITIZER_ANDROID +#endif // SANITIZER_ANDROID void LogMessageOnPrintf(const char *str) { if (common_flags()->log_to_syslog && ShouldLogAfterPrintf()) @@ -776,7 +805,7 @@ void LogMessageOnPrintf(const char *str) { // initialized after the vDSO function pointers, so if it exists, is not null // and is not empty, we can use clock_gettime. extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname; -INLINE bool CanUseVDSO() { +inline bool CanUseVDSO() { // Bionic is safe, it checks for the vDSO function pointers to be initialized. if (SANITIZER_ANDROID) return true; @@ -845,6 +874,41 @@ void ReExec() { } #endif // !SANITIZER_OPENBSD +void UnmapFromTo(uptr from, uptr to) { + if (to == from) + return; + CHECK(to >= from); + uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from); + if (UNLIKELY(internal_iserror(res))) { + Report("ERROR: %s failed to unmap 0x%zx (%zd) bytes at address %p\n", + SanitizerToolName, to - from, to - from, (void *)from); + CHECK("unable to unmap" && 0); + } +} + +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, + UNUSED uptr &high_mem_end) { + const uptr granularity = GetMmapGranularity(); + const uptr alignment = + Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); + const uptr left_padding = + Max<uptr>(granularity, 1ULL << min_shadow_base_alignment); + + const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); + const uptr map_size = shadow_size + left_padding + alignment; + + const uptr map_start = (uptr)MmapNoAccess(map_size); + CHECK_NE(map_start, ~(uptr)0); + + const uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); + + UnmapFromTo(map_start, shadow_start - left_padding); + UnmapFromTo(shadow_start + shadow_size, map_start + map_size); + + return shadow_start; +} + } // namespace __sanitizer #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp index 648236e..b127112 100644 --- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp @@ -27,7 +27,6 @@ #include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" #include "sanitizer_platform_limits_posix.h" #include "sanitizer_procmaps.h" #include "sanitizer_ptrauth.h" @@ -38,7 +37,7 @@ extern char **environ; #endif -#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__) +#if defined(__has_include) && __has_include(<os/trace.h>) #define SANITIZER_OS_TRACE 1 #include <os/trace.h> #else @@ -138,6 +137,10 @@ int internal_mprotect(void *addr, uptr length, int prot) { return mprotect(addr, length, prot); } +int internal_madvise(uptr addr, uptr length, int advice) { + return madvise((void *)addr, length, advice); +} + uptr internal_close(fd_t fd) { return close(fd); } @@ -388,7 +391,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, // pthread_get_stacksize_np() returns an incorrect stack size for the main // thread on Mavericks. See // https://github.com/google/sanitizers/issues/261 - if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization && + if ((GetMacosAlignedVersion() >= MacosVersion(10, 9)) && at_initialization && stacksize == (1 << 19)) { struct rlimit rl; CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); @@ -607,68 +610,111 @@ HandleSignalMode GetHandleSignalMode(int signum) { return result; } -MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; +// Offset example: +// XNU 17 -- macOS 10.13 -- iOS 11 -- tvOS 11 -- watchOS 4 +constexpr u16 GetOSMajorKernelOffset() { + if (TARGET_OS_OSX) return 4; + if (TARGET_OS_IOS || TARGET_OS_TV) return 6; + if (TARGET_OS_WATCH) return 13; +} + +using VersStr = char[64]; -MacosVersion GetMacosVersionInternal() { - int mib[2] = { CTL_KERN, KERN_OSRELEASE }; - char version[100]; - uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); - for (uptr i = 0; i < maxlen; i++) version[i] = '\0'; - // Get the version length. - CHECK_NE(internal_sysctl(mib, 2, 0, &len, 0, 0), -1); - CHECK_LT(len, maxlen); - CHECK_NE(internal_sysctl(mib, 2, version, &len, 0, 0), -1); +static void GetOSVersion(VersStr vers) { + uptr len = sizeof(VersStr); + if (SANITIZER_IOSSIM) { + const char *vers_env = GetEnv("SIMULATOR_RUNTIME_VERSION"); + if (!vers_env) { + Report("ERROR: Running in simulator but SIMULATOR_RUNTIME_VERSION env " + "var is not set.\n"); + Die(); + } + len = internal_strlcpy(vers, vers_env, len); + } else { + int res = + internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0); + if (res) { + // Fallback for XNU 17 (macOS 10.13) and below that do not provide the + // `kern.osproductversion` property. + u16 kernel_major = GetDarwinKernelVersion().major; + u16 offset = GetOSMajorKernelOffset(); + CHECK_LE(kernel_major, 17); + CHECK_GE(kernel_major, offset); + u16 os_major = kernel_major - offset; + + auto format = TARGET_OS_OSX ? "10.%d" : "%d.0"; + len = internal_snprintf(vers, len, format, os_major); + } + } + CHECK_LT(len, sizeof(VersStr)); +} - // Expect <major>.<minor>(.<patch>) - CHECK_GE(len, 3); - const char *p = version; - int major = internal_simple_strtoll(p, &p, /*base=*/10); - if (*p != '.') return MACOS_VERSION_UNKNOWN; +void ParseVersion(const char *vers, u16 *major, u16 *minor) { + // Format: <major>.<minor>[.<patch>]\0 + CHECK_GE(internal_strlen(vers), 3); + const char *p = vers; + *major = internal_simple_strtoll(p, &p, /*base=*/10); + CHECK_EQ(*p, '.'); p += 1; - int minor = internal_simple_strtoll(p, &p, /*base=*/10); - if (*p != '.') return MACOS_VERSION_UNKNOWN; - - switch (major) { - case 11: return MACOS_VERSION_LION; - case 12: return MACOS_VERSION_MOUNTAIN_LION; - case 13: return MACOS_VERSION_MAVERICKS; - case 14: return MACOS_VERSION_YOSEMITE; - case 15: return MACOS_VERSION_EL_CAPITAN; - case 16: return MACOS_VERSION_SIERRA; - case 17: return MACOS_VERSION_HIGH_SIERRA; - case 18: return MACOS_VERSION_MOJAVE; - case 19: return MACOS_VERSION_CATALINA; - default: - if (major < 9) return MACOS_VERSION_UNKNOWN; - return MACOS_VERSION_UNKNOWN_NEWER; + *minor = internal_simple_strtoll(p, &p, /*base=*/10); +} + +// Aligned versions example: +// macOS 10.15 -- iOS 13 -- tvOS 13 -- watchOS 6 +static void MapToMacos(u16 *major, u16 *minor) { + if (TARGET_OS_OSX) + return; + + if (TARGET_OS_IOS || TARGET_OS_TV) + *major += 2; + else if (TARGET_OS_WATCH) + *major += 9; + else + UNREACHABLE("unsupported platform"); + + if (*major >= 16) { // macOS 11+ + *major -= 5; + } else { // macOS 10.15 and below + *minor = *major; + *major = 10; } } -MacosVersion GetMacosVersion() { - atomic_uint32_t *cache = - reinterpret_cast<atomic_uint32_t*>(&cached_macos_version); - MacosVersion result = - static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire)); - if (result == MACOS_VERSION_UNINITIALIZED) { - result = GetMacosVersionInternal(); - atomic_store(cache, result, memory_order_release); +static MacosVersion GetMacosAlignedVersionInternal() { + VersStr vers; + GetOSVersion(vers); + + u16 major, minor; + ParseVersion(vers, &major, &minor); + MapToMacos(&major, &minor); + + return MacosVersion(major, minor); +} + +static_assert(sizeof(MacosVersion) == sizeof(atomic_uint32_t::Type), + "MacosVersion cache size"); +static atomic_uint32_t cached_macos_version; + +MacosVersion GetMacosAlignedVersion() { + atomic_uint32_t::Type result = + atomic_load(&cached_macos_version, memory_order_acquire); + if (!result) { + MacosVersion version = GetMacosAlignedVersionInternal(); + result = *reinterpret_cast<atomic_uint32_t::Type *>(&version); + atomic_store(&cached_macos_version, result, memory_order_release); } - return result; + return *reinterpret_cast<MacosVersion *>(&result); } DarwinKernelVersion GetDarwinKernelVersion() { - char buf[100]; - size_t len = sizeof(buf); - int res = internal_sysctlbyname("kern.osrelease", buf, &len, nullptr, 0); + VersStr vers; + uptr len = sizeof(VersStr); + int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0); CHECK_EQ(res, 0); + CHECK_LT(len, sizeof(VersStr)); - // Format: <major>.<minor>.<patch>\0 - CHECK_GE(len, 6); - const char *p = buf; - u16 major = internal_simple_strtoll(p, &p, /*base=*/10); - CHECK_EQ(*p, '.'); - p += 1; - u16 minor = internal_simple_strtoll(p, &p, /*base=*/10); + u16 major, minor; + ParseVersion(vers, &major, &minor); return DarwinKernelVersion(major, minor); } @@ -719,7 +765,7 @@ void LogFullErrorReport(const char *buffer) { #if !SANITIZER_GO // Log with os_trace. This will make it into the crash log. #if SANITIZER_OS_TRACE - if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) { + if (GetMacosAlignedVersion() >= MacosVersion(10, 10)) { // os_trace requires the message (format parameter) to be a string literal. if (internal_strncmp(SanitizerToolName, "AddressSanitizer", sizeof("AddressSanitizer") - 1) == 0) @@ -808,6 +854,19 @@ void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } +// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers +// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+). +static void DisableMmapExcGuardExceptions() { + using task_exc_guard_behavior_t = uint32_t; + using task_set_exc_guard_behavior_t = + kern_return_t(task_t task, task_exc_guard_behavior_t behavior); + auto *set_behavior = (task_set_exc_guard_behavior_t *)dlsym( + 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); +} + void InitializePlatformEarly() { // Only use xnu_fast_mmap when on x86_64 and the kernel supports it. use_xnu_fast_mmap = @@ -816,6 +875,8 @@ void InitializePlatformEarly() { #else false; #endif + if (GetDarwinKernelVersion() >= DarwinKernelVersion(19, 0)) + DisableMmapExcGuardExceptions(); } #if !SANITIZER_GO @@ -856,20 +917,10 @@ bool ReexecDisabled() { return false; } -extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber; -static const double kMinDyldVersionWithAutoInterposition = 360.0; - -bool DyldNeedsEnvVariable() { - // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users - // still may want use them on older systems. On older Darwin platforms, dyld - // doesn't export dyldVersionNumber symbol and we simply return true. - if (!&dyldVersionNumber) return true; +static bool DyldNeedsEnvVariable() { // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if - // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via - // GetMacosVersion() doesn't work for the simulator. Let's instead check - // `dyldVersionNumber`, which is exported by dyld, against a known version - // number from the first OS release where this appeared. - return dyldVersionNumber < kMinDyldVersionWithAutoInterposition; + // DYLD_INSERT_LIBRARIES is not set. + return GetMacosAlignedVersion() < MacosVersion(10, 11); } void MaybeReexec() { @@ -1082,6 +1133,53 @@ uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); } +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, uptr &high_mem_end) { + const uptr granularity = GetMmapGranularity(); + const uptr alignment = + Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); + const uptr left_padding = + Max<uptr>(granularity, 1ULL << min_shadow_base_alignment); + + uptr space_size = shadow_size_bytes + left_padding; + + uptr largest_gap_found = 0; + uptr max_occupied_addr = 0; + VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); + uptr shadow_start = + FindAvailableMemoryRange(space_size, alignment, granularity, + &largest_gap_found, &max_occupied_addr); + // If the shadow doesn't fit, restrict the address space to make it fit. + if (shadow_start == 0) { + VReport( + 2, + "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n", + largest_gap_found, max_occupied_addr); + uptr new_max_vm = RoundDownTo(largest_gap_found << shadow_scale, alignment); + 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", + space_size, largest_gap_found, max_occupied_addr, new_max_vm); + CHECK(0 && "cannot place shadow"); + } + RestrictMemoryToMaxAddress(new_max_vm); + high_mem_end = new_max_vm - 1; + space_size = (high_mem_end >> shadow_scale) + left_padding; + VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); + shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity, + nullptr, nullptr); + if (shadow_start == 0) { + Report("Unable to find a memory range after restricting VM.\n"); + CHECK(0 && "cannot place shadow after restricting vm"); + } + } + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + return shadow_start; +} + uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, uptr *largest_gap_found, uptr *max_occupied_addr) { diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h index 34dc2c0..023071e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_mac.h +++ b/libsanitizer/sanitizer_common/sanitizer_mac.h @@ -30,37 +30,32 @@ struct MemoryMappingLayoutData { bool current_instrumented; }; -enum MacosVersion { - MACOS_VERSION_UNINITIALIZED = 0, - MACOS_VERSION_UNKNOWN, - MACOS_VERSION_LION, // macOS 10.7; oldest currently supported - MACOS_VERSION_MOUNTAIN_LION, - MACOS_VERSION_MAVERICKS, - MACOS_VERSION_YOSEMITE, - MACOS_VERSION_EL_CAPITAN, - MACOS_VERSION_SIERRA, - MACOS_VERSION_HIGH_SIERRA, - MACOS_VERSION_MOJAVE, - MACOS_VERSION_CATALINA, - MACOS_VERSION_UNKNOWN_NEWER -}; - -struct DarwinKernelVersion { +template <typename VersionType> +struct VersionBase { u16 major; u16 minor; - DarwinKernelVersion(u16 major, u16 minor) : major(major), minor(minor) {} + VersionBase(u16 major, u16 minor) : major(major), minor(minor) {} - bool operator==(const DarwinKernelVersion &other) const { + bool operator==(const VersionType &other) const { return major == other.major && minor == other.minor; } - bool operator>=(const DarwinKernelVersion &other) const { - return major >= other.major || + bool operator>=(const VersionType &other) const { + return major > other.major || (major == other.major && minor >= other.minor); } + bool operator<(const VersionType &other) const { return !(*this >= other); } +}; + +struct MacosVersion : VersionBase<MacosVersion> { + MacosVersion(u16 major, u16 minor) : VersionBase(major, minor) {} +}; + +struct DarwinKernelVersion : VersionBase<DarwinKernelVersion> { + DarwinKernelVersion(u16 major, u16 minor) : VersionBase(major, minor) {} }; -MacosVersion GetMacosVersion(); +MacosVersion GetMacosAlignedVersion(); DarwinKernelVersion GetDarwinKernelVersion(); char **GetEnviron(); @@ -80,7 +75,7 @@ asm(".desc ___crashreporter_info__, 0x10"); namespace __sanitizer { static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED); -INLINE void CRAppendCrashLogMessage(const char *msg) { +inline void CRAppendCrashLogMessage(const char *msg) { BlockingMutexLock l(&crashreporter_info_mutex); internal_strlcat(__crashreporter_info_buff__, msg, sizeof(__crashreporter_info_buff__)); } diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp index d9aff51..98ac736 100644 --- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp @@ -110,6 +110,11 @@ int internal_mprotect(void *addr, uptr length, int prot) { return _REAL(mprotect, addr, length, prot); } +int internal_madvise(uptr addr, uptr length, int advice) { + DEFINE__REAL(int, madvise, void *a, uptr b, int c); + return _REAL(madvise, (void *)addr, length, advice); +} + uptr internal_close(fd_t fd) { CHECK(&_sys_close); return _sys_close(fd); diff --git a/libsanitizer/sanitizer_common/sanitizer_openbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_openbsd.cpp index ed2d8ed..1959017 100644 --- a/libsanitizer/sanitizer_common/sanitizer_openbsd.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_openbsd.cpp @@ -52,6 +52,10 @@ int internal_mprotect(void *addr, uptr length, int prot) { return mprotect(addr, length, prot); } +int internal_madvise(uptr addr, uptr length, int advice) { + return madvise((void *)addr, length, advice); +} + int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, const void *newp, uptr newlen) { Printf("internal_sysctlbyname not implemented for OpenBSD"); diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h index c68bfa2..5547c68 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform.h @@ -132,6 +132,12 @@ # define SANITIZER_X32 0 #endif +#if defined(__i386__) || defined(_M_IX86) +# define SANITIZER_I386 1 +#else +# define SANITIZER_I386 0 +#endif + #if defined(__mips__) # define SANITIZER_MIPS 1 # if defined(__mips64) @@ -213,6 +219,12 @@ # define SANITIZER_MYRIAD2 0 #endif +#if defined(__riscv) && (__riscv_xlen == 64) +#define SANITIZER_RISCV64 1 +#else +#define SANITIZER_RISCV64 0 +#endif + // By default we allow to use SizeClassAllocator64 on 64-bit platform. // But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64 // does not work well and we need to fallback to SizeClassAllocator32. @@ -233,6 +245,8 @@ // will still work but will consume more memory for TwoLevelByteMap. #if defined(__mips__) # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40) +#elif SANITIZER_RISCV64 +#define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 38) #elif defined(__aarch64__) # if SANITIZER_MAC // Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h index 9dd6d28..37f178a 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h @@ -15,6 +15,7 @@ #include "sanitizer_glibc_version.h" #include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" #if SANITIZER_POSIX # define SI_POSIX 1 @@ -240,6 +241,7 @@ (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_CLOCK_GETTIME \ (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX || SI_SOLARIS) +#define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID SI_LINUX #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX #define SANITIZER_INTERCEPT_TIME SI_POSIX #define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS @@ -270,16 +272,17 @@ #define SANITIZER_INTERCEPT_SENDMSG SI_POSIX #define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX #define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX +#define SANITIZER_INTERCEPT_SYSMSG SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX #define SANITIZER_INTERCEPT_IOCTL SI_POSIX #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX #define SANITIZER_INTERCEPT_READDIR SI_POSIX #define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 -#if SI_LINUX_NOT_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__)) +#if SI_LINUX_NOT_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__) || SANITIZER_RISCV64) #define SANITIZER_INTERCEPT_PTRACE 1 #else #define SANITIZER_INTERCEPT_PTRACE 0 @@ -331,6 +334,7 @@ #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_SIGSETOPS \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_SIGSET_LOGICOPS SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGPENDING SI_POSIX #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX @@ -341,7 +345,7 @@ #define SANITIZER_INTERCEPT_STATFS \ (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_STATFS64 \ - ((SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID) + (((SI_MAC && !TARGET_CPU_ARM64) && !SI_IOS) || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_STATVFS \ (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID @@ -381,6 +385,8 @@ #define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD #define SANITIZER_INTERCEPT_TMPNAM SI_POSIX #define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_PTSNAME SI_LINUX +#define SANITIZER_INTERCEPT_PTSNAME_R SI_LINUX #define SANITIZER_INTERCEPT_TTYNAME SI_POSIX #define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX #define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX @@ -437,6 +443,7 @@ #define SANITIZER_INTERCEPT_FTIME \ (!SI_FREEBSD && !SI_NETBSD && !SI_OPENBSD && SI_POSIX) #define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_XDRREC SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TSEARCH \ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) #define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID @@ -494,17 +501,17 @@ #define SANITIZER_INTERCEPT_MMAP SI_POSIX #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ +#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ - SI_NOT_RTEMS) + SI_NOT_RTEMS && !SI_SOLARIS) // NOLINT #define SANITIZER_INTERCEPT_MEMALIGN \ (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS) -#define SANITIZER_INTERCEPT_PVALLOC \ +#define SANITIZER_INTERCEPT_PVALLOC \ (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ - SI_NOT_RTEMS) -#define SANITIZER_INTERCEPT_CFREE \ + SI_NOT_RTEMS && !SI_SOLARIS) // NOLINT +#define SANITIZER_INTERCEPT_CFREE \ (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ - SI_NOT_RTEMS) + SI_NOT_RTEMS && !SI_SOLARIS) // NOLINT #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS) #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE \ @@ -544,7 +551,8 @@ #define SANITIZER_INTERCEPT_FGETLN (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_TTYENT SI_NETBSD -#define SANITIZER_INTERCEPT_PROTOENT SI_NETBSD +#define SANITIZER_INTERCEPT_PROTOENT (SI_NETBSD || SI_LINUX) +#define SANITIZER_INTERCEPT_PROTOENT_R (SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_NETENT SI_NETBSD #define SANITIZER_INTERCEPT_SETVBUF (SI_NETBSD || SI_FREEBSD || \ SI_LINUX || SI_MAC) @@ -596,7 +604,10 @@ #define SANITIZER_INTERCEPT_QSORT \ (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID) #define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID) -#define SANITIZER_INTERCEPT_SIGALTSTACK SI_POSIX +// sigaltstack on i386 macOS cannot be intercepted due to setjmp() +// calling it and assuming that it does not clobber registers. +#define SANITIZER_INTERCEPT_SIGALTSTACK \ + (SI_POSIX && !(SANITIZER_MAC && SANITIZER_I386)) #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp index dcc6c71..b1c15be 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp @@ -81,8 +81,6 @@ #include <sys/shm.h> #undef _KERNEL -#undef INLINE // to avoid clashes with sanitizers' definitions - #undef IOC_DIRMASK // Include these after system headers to avoid name clashes and ambiguities. diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp index f22f503..c51327e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp @@ -26,12 +26,9 @@ // With old kernels (and even new kernels on powerpc) asm/stat.h uses types that // are not defined anywhere in userspace headers. Fake them. This seems to work -// fine with newer headers, too. Beware that with <sys/stat.h>, struct stat -// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64. -// Also, for some platforms (e.g. mips) there are additional members in the -// <sys/stat.h> struct stat:s. +// fine with newer headers, too. #include <linux/posix_types.h> -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__mips__) #include <sys/stat.h> #else #define ino_t __kernel_ino_t diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp index 25da334..c8f2aa5 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp @@ -34,6 +34,7 @@ #include <sys/chio.h> #include <sys/clockctl.h> #include <sys/cpuio.h> +#include <sys/dkbad.h> #include <sys/dkio.h> #include <sys/drvctlio.h> #include <sys/dvdio.h> @@ -83,6 +84,7 @@ #include <sys/resource.h> #include <sys/sem.h> +#include <sys/scsiio.h> #include <sys/sha1.h> #include <sys/sha2.h> #include <sys/shm.h> @@ -139,7 +141,158 @@ #include <dev/ir/irdaio.h> #include <dev/isa/isvio.h> #include <dev/isa/wtreg.h> +#if __has_include(<dev/iscsi/iscsi_ioctl.h>) #include <dev/iscsi/iscsi_ioctl.h> +#else +/* Fallback for MKISCSI=no */ + +typedef struct { + uint32_t status; + uint32_t session_id; + uint32_t connection_id; +} iscsi_conn_status_parameters_t; + +typedef struct { + uint32_t status; + uint16_t interface_version; + uint16_t major; + uint16_t minor; + uint8_t version_string[224]; +} iscsi_get_version_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; + uint32_t connection_id; + struct { + unsigned int immediate : 1; + } options; + uint64_t lun; + scsireq_t req; /* from <sys/scsiio.h> */ +} iscsi_iocommand_parameters_t; + +typedef enum { + ISCSI_AUTH_None = 0, + ISCSI_AUTH_CHAP = 1, + ISCSI_AUTH_KRB5 = 2, + ISCSI_AUTH_SRP = 3 +} iscsi_auth_types_t; + +typedef enum { + ISCSI_LOGINTYPE_DISCOVERY = 0, + ISCSI_LOGINTYPE_NOMAP = 1, + ISCSI_LOGINTYPE_MAP = 2 +} iscsi_login_session_type_t; + +typedef enum { ISCSI_DIGEST_None = 0, ISCSI_DIGEST_CRC32C = 1 } iscsi_digest_t; + +typedef enum { + ISCSI_SESSION_TERMINATED = 1, + ISCSI_CONNECTION_TERMINATED, + ISCSI_RECOVER_CONNECTION, + ISCSI_DRIVER_TERMINATING +} iscsi_event_t; + +typedef struct { + unsigned int mutual_auth : 1; + unsigned int is_secure : 1; + unsigned int auth_number : 4; + iscsi_auth_types_t auth_type[4]; +} iscsi_auth_info_t; + +typedef struct { + uint32_t status; + int socket; + struct { + unsigned int HeaderDigest : 1; + unsigned int DataDigest : 1; + unsigned int MaxConnections : 1; + unsigned int DefaultTime2Wait : 1; + unsigned int DefaultTime2Retain : 1; + unsigned int MaxRecvDataSegmentLength : 1; + unsigned int auth_info : 1; + unsigned int user_name : 1; + unsigned int password : 1; + unsigned int target_password : 1; + unsigned int TargetName : 1; + unsigned int TargetAlias : 1; + unsigned int ErrorRecoveryLevel : 1; + } is_present; + iscsi_auth_info_t auth_info; + iscsi_login_session_type_t login_type; + iscsi_digest_t HeaderDigest; + iscsi_digest_t DataDigest; + uint32_t session_id; + uint32_t connection_id; + uint32_t MaxRecvDataSegmentLength; + uint16_t MaxConnections; + uint16_t DefaultTime2Wait; + uint16_t DefaultTime2Retain; + uint16_t ErrorRecoveryLevel; + void *user_name; + void *password; + void *target_password; + void *TargetName; + void *TargetAlias; +} iscsi_login_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; +} iscsi_logout_parameters_t; + +typedef struct { + uint32_t status; + uint32_t event_id; +} iscsi_register_event_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; + uint32_t connection_id; +} iscsi_remove_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; + void *response_buffer; + uint32_t response_size; + uint32_t response_used; + uint32_t response_total; + uint8_t key[224]; +} iscsi_send_targets_parameters_t; + +typedef struct { + uint32_t status; + uint8_t InitiatorName[224]; + uint8_t InitiatorAlias[224]; + uint8_t ISID[6]; +} iscsi_set_node_name_parameters_t; + +typedef struct { + uint32_t status; + uint32_t event_id; + iscsi_event_t event_kind; + uint32_t session_id; + uint32_t connection_id; + uint32_t reason; +} iscsi_wait_event_parameters_t; + +#define ISCSI_GET_VERSION _IOWR(0, 1, iscsi_get_version_parameters_t) +#define ISCSI_LOGIN _IOWR(0, 2, iscsi_login_parameters_t) +#define ISCSI_LOGOUT _IOWR(0, 3, iscsi_logout_parameters_t) +#define ISCSI_ADD_CONNECTION _IOWR(0, 4, iscsi_login_parameters_t) +#define ISCSI_RESTORE_CONNECTION _IOWR(0, 5, iscsi_login_parameters_t) +#define ISCSI_REMOVE_CONNECTION _IOWR(0, 6, iscsi_remove_parameters_t) +#define ISCSI_CONNECTION_STATUS _IOWR(0, 7, iscsi_conn_status_parameters_t) +#define ISCSI_SEND_TARGETS _IOWR(0, 8, iscsi_send_targets_parameters_t) +#define ISCSI_SET_NODE_NAME _IOWR(0, 9, iscsi_set_node_name_parameters_t) +#define ISCSI_IO_COMMAND _IOWR(0, 10, iscsi_iocommand_parameters_t) +#define ISCSI_REGISTER_EVENT _IOWR(0, 11, iscsi_register_event_parameters_t) +#define ISCSI_DEREGISTER_EVENT _IOWR(0, 12, iscsi_register_event_parameters_t) +#define ISCSI_WAIT_EVENT _IOWR(0, 13, iscsi_wait_event_parameters_t) +#define ISCSI_POLL_EVENT _IOWR(0, 14, iscsi_wait_event_parameters_t) +#endif #include <dev/ofw/openfirmio.h> #include <dev/pci/amrio.h> #include <dev/pci/mlyreg.h> @@ -372,7 +525,7 @@ struct urio_command { #include "sanitizer_platform_limits_netbsd.h" namespace __sanitizer { -void *__sanitizer_get_link_map_by_dlopen_handle(void* handle) { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) { void *p = nullptr; return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr; } diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h index d80280d..9e28dcf 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -21,8 +21,8 @@ namespace __sanitizer { void *__sanitizer_get_link_map_by_dlopen_handle(void *handle); -# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) extern unsigned struct_utsname_sz; extern unsigned struct_stat_sz; @@ -1024,12 +1024,10 @@ extern unsigned struct_RF_ProgressInfo_sz; extern unsigned struct_nvlist_ref_sz; extern unsigned struct_StringList_sz; - // A special value to mark ioctls that are not present on the target platform, // when it can not be determined without including any system headers. extern const unsigned IOCTL_NOT_PRESENT; - extern unsigned IOCTL_AFM_ADDFMAP; extern unsigned IOCTL_AFM_DELFMAP; extern unsigned IOCTL_AFM_CLEANFMAP; diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp index e71515f..1427cec 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -90,7 +90,8 @@ #if SANITIZER_LINUX # include <utime.h> # include <sys/ptrace.h> -# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) +#if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \ + SANITIZER_RISCV64 # include <asm/ptrace.h> # ifdef __arm__ typedef struct user_fpregs elf_fpregset_t; @@ -170,9 +171,9 @@ typedef struct user_fpregs elf_fpregset_t; namespace __sanitizer { unsigned struct_utsname_sz = sizeof(struct utsname); unsigned struct_stat_sz = sizeof(struct stat); -#if !SANITIZER_IOS +#if !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64) unsigned struct_stat64_sz = sizeof(struct stat64); -#endif // !SANITIZER_IOS +#endif // !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64) unsigned struct_rusage_sz = sizeof(struct rusage); unsigned struct_tm_sz = sizeof(struct tm); unsigned struct_passwd_sz = sizeof(struct passwd); @@ -197,9 +198,9 @@ namespace __sanitizer { unsigned struct_regex_sz = sizeof(regex_t); unsigned struct_regmatch_sz = sizeof(regmatch_t); -#if SANITIZER_MAC && !SANITIZER_IOS +#if (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS unsigned struct_statfs64_sz = sizeof(struct statfs64); -#endif // SANITIZER_MAC && !SANITIZER_IOS +#endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS #if !SANITIZER_ANDROID unsigned struct_fstab_sz = sizeof(struct fstab); @@ -229,9 +230,9 @@ namespace __sanitizer { #if SANITIZER_LINUX && !SANITIZER_ANDROID // Use pre-computed size of struct ustat to avoid <sys/ustat.h> which // has been removed from glibc 2.28. -#if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \ - || defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \ - || defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) +#if defined(__aarch64__) || defined(__s390x__) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) || \ + defined(__x86_64__) || SANITIZER_RISCV64 #define SIZEOF_STRUCT_USTAT 32 #elif defined(__arm__) || defined(__i386__) || defined(__mips__) \ || defined(__powerpc__) || defined(__s390__) || defined(__sparc__) @@ -303,13 +304,16 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); int glob_altdirfunc = GLOB_ALTDIRFUNC; #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__)) +#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__) || SANITIZER_RISCV64) #if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); +#elif SANITIZER_RISCV64 + unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); + unsigned struct_user_fpregs_struct_sz = sizeof(struct __riscv_q_ext_state); #elif defined(__aarch64__) unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs); unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state); @@ -321,7 +325,8 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); #endif // __mips64 || __powerpc64__ || __aarch64__ #if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ - defined(__aarch64__) || defined(__arm__) || defined(__s390__) + defined(__aarch64__) || defined(__arm__) || defined(__s390__) || \ + SANITIZER_RISCV64 unsigned struct_user_fpxregs_struct_sz = 0; #else unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h index 7a992d5..e69560e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h @@ -83,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104; #elif defined(__mips__) const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID ? FIRST_32_SECOND_64(104, 128) - : FIRST_32_SECOND_64(144, 216); + : FIRST_32_SECOND_64(160, 216); const unsigned struct_kernel_stat64_sz = 104; #elif defined(__s390__) && !defined(__s390x__) const unsigned struct_kernel_stat_sz = 64; @@ -99,9 +99,9 @@ const unsigned struct_kernel_stat64_sz = 144; const unsigned struct___old_kernel_stat_sz = 0; const unsigned struct_kernel_stat_sz = 64; const unsigned struct_kernel_stat64_sz = 104; -#elif defined(__riscv) && __riscv_xlen == 64 +#elif SANITIZER_RISCV64 const unsigned struct_kernel_stat_sz = 128; -const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat64_sz = 0; // RISCV64 does not use stat64 #endif struct __sanitizer_perf_event_attr { unsigned type; @@ -704,6 +704,12 @@ struct __sanitizer_dl_phdr_info { extern unsigned struct_ElfW_Phdr_sz; #endif +struct __sanitizer_protoent { + char *p_name; + char **p_aliases; + int p_proto; +}; + struct __sanitizer_addrinfo { int ai_flags; int ai_family; @@ -798,7 +804,7 @@ typedef void __sanitizer_FILE; #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__)) + defined(__s390__) || SANITIZER_RISCV64) extern unsigned struct_user_regs_struct_sz; extern unsigned struct_user_fpregs_struct_sz; extern unsigned struct_user_fpxregs_struct_sz; diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp index 6ec1a1b..565b31f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp @@ -202,7 +202,8 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); -CHECK_TYPE_SIZE(glob_t); +// There are additional fields we are not interested in. +COMPILER_CHECK(sizeof(__sanitizer_glob_t) <= sizeof(glob_t)); CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp index e21661b..b8b75c2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp @@ -293,7 +293,7 @@ uptr SignalContext::GetAddress() const { bool SignalContext::IsMemoryAccess() const { auto si = static_cast<const siginfo_t *>(siginfo); - return si->si_signo == SIGSEGV; + return si->si_signo == SIGSEGV || si->si_signo == SIGBUS; } int SignalContext::GetType() const { @@ -354,11 +354,11 @@ int GetNamedMappingFd(const char *name, uptr size, int *flags) { int fd = ReserveStandardFds( internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU)); CHECK_GE(fd, 0); - if (!o_cloexec) { - int res = fcntl(fd, F_SETFD, FD_CLOEXEC); - CHECK_EQ(0, res); - } int res = internal_ftruncate(fd, size); +#if !defined(O_CLOEXEC) + res = fcntl(fd, F_SETFD, FD_CLOEXEC); + CHECK_EQ(0, res); +#endif CHECK_EQ(0, res); res = internal_unlink(shmname); CHECK_EQ(0, res); diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h index a1b4970..66bcaf4 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.h +++ b/libsanitizer/sanitizer_common/sanitizer_posix.h @@ -42,6 +42,7 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset); uptr internal_munmap(void *addr, uptr length); int internal_mprotect(void *addr, uptr length, int prot); +int internal_madvise(uptr addr, uptr length, int advice); // OS uptr internal_filesize(fd_t fd); // -1 on error. diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp index f920172..37aaec3 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -61,27 +61,24 @@ void ReleaseMemoryPagesToOS(uptr beg, uptr end) { uptr beg_aligned = RoundUpTo(beg, page_size); uptr end_aligned = RoundDownTo(end, page_size); if (beg_aligned < end_aligned) - // In the default Solaris compilation environment, madvise() is declared - // to take a caddr_t arg; casting it to void * results in an invalid - // conversion error, so use char * instead. - madvise((char *)beg_aligned, end_aligned - beg_aligned, - SANITIZER_MADVISE_DONTNEED); + internal_madvise(beg_aligned, end_aligned - beg_aligned, + SANITIZER_MADVISE_DONTNEED); } void SetShadowRegionHugePageMode(uptr addr, uptr size) { #ifdef MADV_NOHUGEPAGE // May not be defined on old systems. if (common_flags()->no_huge_pages_for_shadow) - madvise((char *)addr, size, MADV_NOHUGEPAGE); + internal_madvise(addr, size, MADV_NOHUGEPAGE); else - madvise((char *)addr, size, MADV_HUGEPAGE); + internal_madvise(addr, size, MADV_HUGEPAGE); #endif // MADV_NOHUGEPAGE } bool DontDumpShadowMemory(uptr addr, uptr length) { #if defined(MADV_DONTDUMP) - return madvise((char *)addr, length, MADV_DONTDUMP) == 0; + return internal_madvise(addr, length, MADV_DONTDUMP) == 0; #elif defined(MADV_NOCORE) - return madvise((char *)addr, length, MADV_NOCORE) == 0; + return internal_madvise(addr, length, MADV_NOCORE) == 0; #else return true; #endif // MADV_DONTDUMP diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp index 8793423..4063ec8 100644 --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp @@ -35,7 +35,8 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; if (data_.current >= last) return false; - prxmap_t *xmapentry = (prxmap_t*)data_.current; + prxmap_t *xmapentry = + const_cast<prxmap_t *>(reinterpret_cast<const prxmap_t *>(data_.current)); segment->start = (uptr)xmapentry->pr_vaddr; segment->end = (uptr)(xmapentry->pr_vaddr + xmapentry->pr_size); diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h index 4d0d96a..a288068 100644 --- a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h +++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h @@ -18,4 +18,6 @@ #define ptrauth_string_discriminator(__string) ((int)0) #endif +#define STRIP_PC(pc) ((uptr)ptrauth_strip(pc, 0)) + #endif // SANITIZER_PTRAUTH_H diff --git a/libsanitizer/sanitizer_common/sanitizer_signal_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_signal_interceptors.inc index 68d9eb6..cefb870 100644 --- a/libsanitizer/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/libsanitizer/sanitizer_common/sanitizer_signal_interceptors.inc @@ -53,7 +53,10 @@ INTERCEPTOR(uptr, signal, int signum, uptr handler) { INTERCEPTOR(int, sigaction_symname, int signum, const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { - if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) { + if (!oldact) return 0; + act = nullptr; + } SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); } #define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname) diff --git a/libsanitizer/sanitizer_common/sanitizer_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_solaris.cpp index 035f2d0..8789dcd 100644 --- a/libsanitizer/sanitizer_common/sanitizer_solaris.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_solaris.cpp @@ -74,6 +74,20 @@ DECLARE__REAL_AND_INTERNAL(int, mprotect, void *addr, uptr length, int prot) { return _REAL(mprotect)(addr, length, prot); } +// Illumos' declaration of madvise cannot be made visible if _XOPEN_SOURCE +// is defined as g++ does on Solaris. +// +// This declaration is consistent with Solaris 11.4. Both Illumos and Solaris +// versions older than 11.4 declared madvise with a caddr_t as the first +// argument, but we don't currently support Solaris versions older than 11.4, +// and as mentioned above the declaration is not visible on Illumos so we can +// use any declaration we like on Illumos. +extern "C" int madvise(void *, size_t, int); + +int internal_madvise(uptr addr, uptr length, int advice) { + return madvise((void *)addr, length, advice); +} + DECLARE__REAL_AND_INTERNAL(uptr, close, fd_t fd) { return _REAL(close)(fd); } @@ -146,10 +160,6 @@ DECLARE__REAL_AND_INTERNAL(uptr, sched_yield, void) { return sched_yield(); } -DECLARE__REAL_AND_INTERNAL(void, _exit, int exitcode) { - _exit(exitcode); -} - DECLARE__REAL_AND_INTERNAL(uptr, execve, const char *filename, char *const argv[], char *const envp[]) { return _REAL(execve)(filename, argv, envp); diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp index 30073a9..4692f50 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp @@ -115,6 +115,12 @@ void StackDepotUnlockAll() { theDepot.UnlockAll(); } +void StackDepotPrintAll() { +#if !SANITIZER_GO + theDepot.PrintAll(); +#endif +} + bool StackDepotReverseMap::IdDescPair::IdComparator( const StackDepotReverseMap::IdDescPair &a, const StackDepotReverseMap::IdDescPair &b) { diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h index bf29cb9..0e26c1f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h @@ -41,6 +41,7 @@ StackTrace StackDepotGet(u32 id); void StackDepotLockAll(); void StackDepotUnlockAll(); +void StackDepotPrintAll(); // Instantiating this class creates a snapshot of StackDepot which can be // efficiently queried with StackDepotGet(). You can use it concurrently with diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h b/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h index ef1b4f7..1af2c18 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h @@ -13,9 +13,11 @@ #ifndef SANITIZER_STACKDEPOTBASE_H #define SANITIZER_STACKDEPOTBASE_H +#include <stdio.h> + +#include "sanitizer_atomic.h" #include "sanitizer_internal_defs.h" #include "sanitizer_mutex.h" -#include "sanitizer_atomic.h" #include "sanitizer_persistent_allocator.h" namespace __sanitizer { @@ -34,6 +36,7 @@ class StackDepotBase { void LockAll(); void UnlockAll(); + void PrintAll(); private: static Node *find(Node *s, args_type args, u32 hash); @@ -172,6 +175,21 @@ void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() { } } +template <class Node, int kReservedBits, int kTabSizeLog> +void StackDepotBase<Node, kReservedBits, kTabSizeLog>::PrintAll() { + for (int i = 0; i < kTabSize; ++i) { + atomic_uintptr_t *p = &tab[i]; + lock(p); + uptr v = atomic_load(p, memory_order_relaxed); + Node *s = (Node *)(v & ~1UL); + for (; s; s = s->link) { + Printf("Stack for id %u:\n", s->id); + s->load().Print(); + } + unlock(p, s); + } +} + } // namespace __sanitizer #endif // SANITIZER_STACKDEPOTBASE_H diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp index ce75cbe..b0487d8 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp @@ -10,9 +10,11 @@ // run-time libraries. //===----------------------------------------------------------------------===// +#include "sanitizer_stacktrace.h" + #include "sanitizer_common.h" #include "sanitizer_flags.h" -#include "sanitizer_stacktrace.h" +#include "sanitizer_platform.h" namespace __sanitizer { @@ -21,6 +23,28 @@ uptr StackTrace::GetNextInstructionPc(uptr pc) { return pc + 8; #elif defined(__powerpc__) || defined(__arm__) || defined(__aarch64__) return pc + 4; +#elif SANITIZER_RISCV64 + // Current check order is 4 -> 2 -> 6 -> 8 + u8 InsnByte = *(u8 *)(pc); + if (((InsnByte & 0x3) == 0x3) && ((InsnByte & 0x1c) != 0x1c)) { + // xxxxxxxxxxxbbb11 | 32 bit | bbb != 111 + return pc + 4; + } + if ((InsnByte & 0x3) != 0x3) { + // xxxxxxxxxxxxxxaa | 16 bit | aa != 11 + return pc + 2; + } + // RISC-V encoding allows instructions to be up to 8 bytes long + if ((InsnByte & 0x3f) == 0x1f) { + // xxxxxxxxxx011111 | 48 bit | + return pc + 6; + } + if ((InsnByte & 0x7f) == 0x3f) { + // xxxxxxxxx0111111 | 64 bit | + return pc + 8; + } + // bail-out if could not figure out the instruction size + return 0; #else return pc + 1; #endif @@ -60,8 +84,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp, // Nope, this does not look right either. This means the frame after next does // not have a valid frame pointer, but we can still extract the caller PC. // Unfortunately, there is no way to decide between GCC and LLVM frame - // layouts. Assume GCC. - return bp_prev - 1; + // layouts. Assume LLVM. + return bp_prev; #else return (uhwptr*)bp; #endif @@ -84,23 +108,19 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { #ifdef __powerpc__ - // PowerPC ABIs specify that the return address is saved on the - // *caller's* stack frame. Thus we must dereference the back chain - // to find the caller frame before extracting it. + // PowerPC ABIs specify that the return address is saved at offset + // 16 of the *caller's* stack frame. Thus we must dereference the + // back chain to find the caller frame before extracting it. uhwptr *caller_frame = (uhwptr*)frame[0]; if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || !IsAligned((uptr)caller_frame, sizeof(uhwptr))) break; - // For most ABIs the offset where the return address is saved is two - // register sizes. The exception is the SVR4 ABI, which uses an - // offset of only one register size. -#ifdef _CALL_SYSV - uhwptr pc1 = caller_frame[1]; -#else uhwptr pc1 = caller_frame[2]; -#endif #elif defined(__s390__) uhwptr pc1 = frame[14]; +#elif defined(__riscv) + // frame[-1] contains the return address + uhwptr pc1 = frame[-1]; #else uhwptr pc1 = frame[1]; #endif @@ -113,7 +133,13 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, trace_buffer[size++] = (uptr) pc1; } bottom = (uptr)frame; - frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom); +#if defined(__riscv) + // frame[-2] contain fp of the previous frame + uptr new_bp = (uptr)frame[-2]; +#else + uptr new_bp = (uptr)frame[0]; +#endif + frame = GetCanonicFrame(new_bp, stack_top, bottom); } } diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h index f1f29e9..d9fd88d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h @@ -13,6 +13,7 @@ #define SANITIZER_STACKTRACE_H #include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" namespace __sanitizer { @@ -85,6 +86,14 @@ uptr StackTrace::GetPreviousInstructionPc(uptr pc) { return pc - 4; #elif defined(__sparc__) || defined(__mips__) return pc - 8; +#elif SANITIZER_RISCV64 + // RV-64 has variable instruciton length... + // C extentions gives us 2-byte instructoins + // RV-64 has 4-byte instructions + // + RISCV architecture allows instructions up to 8 bytes + // It seems difficult to figure out the exact instruction length - + // pc - 2 seems like a safe option for the purposes of stack tracing + return pc - 2; #else return pc - 1; #endif @@ -143,9 +152,17 @@ struct BufferedStackTrace : public StackTrace { friend class FastUnwindTest; }; +#if defined(__s390x__) +static const uptr kFrameSize = 160; +#elif defined(__s390__) +static const uptr kFrameSize = 96; +#else +static const uptr kFrameSize = 2 * sizeof(uhwptr); +#endif + // Check if given pointer points into allocated stack area. static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) { - return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr); + return frame > stack_bottom && frame < stack_top - kFrameSize; } } // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp index 4ef305c..7808ba9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -26,17 +26,23 @@ void StackTrace::Print() const { InternalScopedString frame_desc(GetPageSizeCached() * 2); InternalScopedString dedup_token(GetPageSizeCached()); int dedup_frames = common_flags()->dedup_token_length; + bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format); uptr frame_num = 0; for (uptr i = 0; i < size && trace[i]; i++) { // PCs in stack traces are actually the return addresses, that is, // addresses of the next instructions after the call. uptr pc = GetPreviousInstructionPc(trace[i]); - SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc); + SymbolizedStack *frames; + if (symbolize) + frames = Symbolizer::GetOrInit()->SymbolizePC(pc); + else + frames = SymbolizedStack::New(pc); CHECK(frames); for (SymbolizedStack *cur = frames; cur; cur = cur->next) { frame_desc.clear(); RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++, - cur->info, common_flags()->symbolize_vs_style, + cur->info.address, symbolize ? &cur->info : nullptr, + common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix); Printf("%s\n", frame_desc.data()); if (dedup_frames-- > 0) { @@ -108,7 +114,12 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, uptr out_buf_size) { if (!out_buf_size) return; pc = StackTrace::GetPreviousInstructionPc(pc); - SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); + SymbolizedStack *frame; + bool symbolize = RenderNeedsSymbolization(fmt); + if (symbolize) + frame = Symbolizer::GetOrInit()->SymbolizePC(pc); + else + frame = SymbolizedStack::New(pc); if (!frame) { internal_strncpy(out_buf, "<can't symbolize>", out_buf_size); out_buf[out_buf_size - 1] = 0; @@ -121,7 +132,8 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, for (SymbolizedStack *cur = frame; cur && out_buf < out_end; cur = cur->next) { frame_desc.clear(); - RenderFrame(&frame_desc, fmt, frame_num++, cur->info, + RenderFrame(&frame_desc, fmt, frame_num++, cur->info.address, + symbolize ? &cur->info : nullptr, common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix); if (!frame_desc.length()) @@ -134,6 +146,7 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, } CHECK(out_buf <= out_end); *out_buf = 0; + frame->ClearAll(); } SANITIZER_INTERFACE_ATTRIBUTE diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cpp index 150ff47..c998322 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cpp @@ -107,8 +107,14 @@ static const char *DemangleFunctionName(const char *function) { static const char kDefaultFormat[] = " #%n %p %F %L"; void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, - const AddressInfo &info, bool vs_style, + uptr address, const AddressInfo *info, bool vs_style, const char *strip_path_prefix, const char *strip_func_prefix) { + // info will be null in the case where symbolization is not needed for the + // given format. This ensures that the code below will get a hard failure + // rather than print incorrect information in case RenderNeedsSymbolization + // ever ends up out of sync with this function. If non-null, the addresses + // should match. + CHECK(!info || address == info->address); if (0 == internal_strcmp(format, "DEFAULT")) format = kDefaultFormat; for (const char *p = format; *p != '\0'; p++) { @@ -126,71 +132,70 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, buffer->append("%zu", frame_no); break; case 'p': - buffer->append("0x%zx", info.address); + buffer->append("0x%zx", address); break; case 'm': - buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); + buffer->append("%s", StripPathPrefix(info->module, strip_path_prefix)); break; case 'o': - buffer->append("0x%zx", info.module_offset); + buffer->append("0x%zx", info->module_offset); break; case 'f': - buffer->append("%s", - DemangleFunctionName( - StripFunctionName(info.function, strip_func_prefix))); + buffer->append("%s", DemangleFunctionName(StripFunctionName( + info->function, strip_func_prefix))); break; case 'q': - buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown - ? info.function_offset + buffer->append("0x%zx", info->function_offset != AddressInfo::kUnknown + ? info->function_offset : 0x0); break; case 's': - buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); + buffer->append("%s", StripPathPrefix(info->file, strip_path_prefix)); break; case 'l': - buffer->append("%d", info.line); + buffer->append("%d", info->line); break; case 'c': - buffer->append("%d", info.column); + buffer->append("%d", info->column); break; // Smarter special cases. case 'F': // Function name and offset, if file is unknown. - if (info.function) { - buffer->append("in %s", - DemangleFunctionName( - StripFunctionName(info.function, strip_func_prefix))); - if (!info.file && info.function_offset != AddressInfo::kUnknown) - buffer->append("+0x%zx", info.function_offset); + if (info->function) { + buffer->append("in %s", DemangleFunctionName(StripFunctionName( + info->function, strip_func_prefix))); + if (!info->file && info->function_offset != AddressInfo::kUnknown) + buffer->append("+0x%zx", info->function_offset); } break; case 'S': // File/line information. - RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style, - strip_path_prefix); + RenderSourceLocation(buffer, info->file, info->line, info->column, + vs_style, strip_path_prefix); break; case 'L': // Source location, or module location. - if (info.file) { - RenderSourceLocation(buffer, info.file, info.line, info.column, + if (info->file) { + RenderSourceLocation(buffer, info->file, info->line, info->column, vs_style, strip_path_prefix); - } else if (info.module) { - RenderModuleLocation(buffer, info.module, info.module_offset, - info.module_arch, strip_path_prefix); + } else if (info->module) { + RenderModuleLocation(buffer, info->module, info->module_offset, + info->module_arch, strip_path_prefix); } else { buffer->append("(<unknown module>)"); } break; case 'M': // Module basename and offset, or PC. - if (info.address & kExternalPCBit) - {} // There PCs are not meaningful. - else if (info.module) + if (address & kExternalPCBit) { + // There PCs are not meaningful. + } else if (info->module) { // Always strip the module name for %M. - RenderModuleLocation(buffer, StripModuleName(info.module), - info.module_offset, info.module_arch, ""); - else - buffer->append("(%p)", (void *)info.address); + RenderModuleLocation(buffer, StripModuleName(info->module), + info->module_offset, info->module_arch, ""); + } else { + buffer->append("(%p)", (void *)address); + } break; default: Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, @@ -200,6 +205,29 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, } } +bool RenderNeedsSymbolization(const char *format) { + if (0 == internal_strcmp(format, "DEFAULT")) + format = kDefaultFormat; + for (const char *p = format; *p != '\0'; p++) { + if (*p != '%') + continue; + p++; + switch (*p) { + case '%': + break; + case 'n': + // frame_no + break; + case 'p': + // address + break; + default: + return true; + } + } + return false; +} + void RenderData(InternalScopedString *buffer, const char *format, const DataInfo *DI, const char *strip_path_prefix) { for (const char *p = format; *p != '\0'; p++) { diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h index f7f7629..96119b2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h @@ -47,10 +47,12 @@ namespace __sanitizer { // module+offset if it is known, or (<unknown module>) string. // %M - prints module basename and offset, if it is known, or PC. void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, - const AddressInfo &info, bool vs_style, + uptr address, const AddressInfo *info, bool vs_style, const char *strip_path_prefix = "", const char *strip_func_prefix = ""); +bool RenderNeedsSymbolization(const char *format); + void RenderSourceLocation(InternalScopedString *buffer, const char *file, int line, int column, bool vs_style, const char *strip_path_prefix); diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h b/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h index 4e42400..7eb7c76 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h @@ -32,13 +32,11 @@ class SuspendedThreadsList { // Can't declare pure virtual functions in sanitizer runtimes: // __cxa_pure_virtual might be unavailable. Use UNIMPLEMENTED() instead. - virtual PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const { + virtual PtraceRegistersStatus GetRegistersAndSP( + uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { UNIMPLEMENTED(); } - // The buffer in GetRegistersAndSP should be at least this big. - virtual uptr RegisterCount() const { UNIMPLEMENTED(); } virtual uptr ThreadCount() const { UNIMPLEMENTED(); } virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); } diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp index 651d505..6a3c004 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp @@ -13,10 +13,10 @@ #include "sanitizer_platform.h" -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \ - defined(__aarch64__) || defined(__powerpc64__) || \ - defined(__s390__) || defined(__i386__) || \ - defined(__arm__)) +#if SANITIZER_LINUX && \ + (defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \ + defined(__arm__) || SANITIZER_RISCV64) #include "sanitizer_stoptheworld.h" @@ -31,7 +31,7 @@ #include <sys/types.h> // for pid_t #include <sys/uio.h> // for iovec #include <elf.h> // for NT_PRSTATUS -#if defined(__aarch64__) && !SANITIZER_ANDROID +#if (defined(__aarch64__) || SANITIZER_RISCV64) && !SANITIZER_ANDROID // GLIBC 2.20+ sys/user does not include asm/ptrace.h # include <asm/ptrace.h> #endif @@ -89,14 +89,14 @@ class SuspendedThreadsListLinux : public SuspendedThreadsList { public: SuspendedThreadsListLinux() { thread_ids_.reserve(1024); } - tid_t GetThreadID(uptr index) const; - uptr ThreadCount() const; + tid_t GetThreadID(uptr index) const override; + uptr ThreadCount() const override; bool ContainsTid(tid_t thread_id) const; void Append(tid_t tid); - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const; - uptr RegisterCount() const; + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector<uptr> *buffer, + uptr *sp) const override; private: InternalMmapVector<tid_t> thread_ids_; @@ -485,6 +485,9 @@ typedef user_regs_struct regs_struct; #else #define REG_SP rsp #endif +#define ARCH_IOVEC_FOR_GETREGSET +// Compiler may use FP registers to store pointers. +static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET}; #elif defined(__powerpc__) || defined(__powerpc64__) typedef pt_regs regs_struct; @@ -501,11 +504,19 @@ typedef struct user regs_struct; #elif defined(__aarch64__) typedef struct user_pt_regs regs_struct; #define REG_SP sp +static constexpr uptr kExtraRegs[] = {0}; +#define ARCH_IOVEC_FOR_GETREGSET + +#elif SANITIZER_RISCV64 +typedef struct user_regs_struct regs_struct; +#define REG_SP sp +static constexpr uptr kExtraRegs[] = {0}; #define ARCH_IOVEC_FOR_GETREGSET #elif defined(__s390__) typedef _user_regs_struct regs_struct; #define REG_SP gprs[15] +static constexpr uptr kExtraRegs[] = {0}; #define ARCH_IOVEC_FOR_GETREGSET #else @@ -533,24 +544,58 @@ void SuspendedThreadsListLinux::Append(tid_t tid) { } PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP( - uptr index, uptr *buffer, uptr *sp) const { + uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { pid_t tid = GetThreadID(index); - regs_struct regs; + constexpr uptr uptr_sz = sizeof(uptr); int pterrno; #ifdef ARCH_IOVEC_FOR_GETREGSET - struct iovec regset_io; - regset_io.iov_base = ®s; - regset_io.iov_len = sizeof(regs_struct); - bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, - (void*)NT_PRSTATUS, (void*)®set_io), - &pterrno); + auto append = [&](uptr regset) { + uptr size = buffer->size(); + // NT_X86_XSTATE requires 64bit alignment. + uptr size_up = RoundUpTo(size, 8 / uptr_sz); + buffer->reserve(Max<uptr>(1024, size_up)); + struct iovec regset_io; + for (;; buffer->resize(buffer->capacity() * 2)) { + buffer->resize(buffer->capacity()); + uptr available_bytes = (buffer->size() - size_up) * uptr_sz; + regset_io.iov_base = buffer->data() + size_up; + regset_io.iov_len = available_bytes; + bool fail = + internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, + (void *)regset, (void *)®set_io), + &pterrno); + if (fail) { + VReport(1, "Could not get regset %p from thread %d (errno %d).\n", + (void *)regset, tid, pterrno); + buffer->resize(size); + return false; + } + + // Far enough from the buffer size, no need to resize and repeat. + if (regset_io.iov_len + 64 < available_bytes) + break; + } + buffer->resize(size_up + RoundUpTo(regset_io.iov_len, uptr_sz) / uptr_sz); + return true; + }; + + buffer->clear(); + bool fail = !append(NT_PRSTATUS); + if (!fail) { + // Accept the first available and do not report errors. + for (uptr regs : kExtraRegs) + if (regs && append(regs)) + break; + } #else - bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, nullptr, - ®s), &pterrno); -#endif - if (isErr) { + buffer->resize(RoundUpTo(sizeof(regs_struct), uptr_sz) / uptr_sz); + bool fail = internal_iserror( + internal_ptrace(PTRACE_GETREGS, tid, nullptr, buffer->data()), &pterrno); + if (fail) VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, pterrno); +#endif + if (fail) { // ESRCH means that the given thread is not suspended or already dead. // Therefore it's unsafe to inspect its data (e.g. walk through stack) and // we should notify caller about this. @@ -558,14 +603,10 @@ PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP( : REGISTERS_UNAVAILABLE; } - *sp = regs.REG_SP; - internal_memcpy(buffer, ®s, sizeof(regs)); + *sp = reinterpret_cast<regs_struct *>(buffer->data())[0].REG_SP; return REGISTERS_AVAILABLE; } -uptr SuspendedThreadsListLinux::RegisterCount() const { - return sizeof(regs_struct) / sizeof(uptr); -} } // namespace __sanitizer #endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp index 6c57742..a605d5b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp @@ -31,15 +31,15 @@ class SuspendedThreadsListMac : public SuspendedThreadsList { public: SuspendedThreadsListMac() : threads_(1024) {} - tid_t GetThreadID(uptr index) const; + tid_t GetThreadID(uptr index) const override; thread_t GetThread(uptr index) const; - uptr ThreadCount() const; + uptr ThreadCount() const override; bool ContainsThread(thread_t thread) const; void Append(thread_t thread); - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const; - uptr RegisterCount() const; + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector<uptr> *buffer, + uptr *sp) const override; private: InternalMmapVector<SuspendedThreadInfo> threads_; @@ -142,7 +142,7 @@ void SuspendedThreadsListMac::Append(thread_t thread) { } PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( - uptr index, uptr *buffer, uptr *sp) const { + uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { thread_t thread = GetThread(index); regs_struct regs; int err; @@ -159,7 +159,8 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( : REGISTERS_UNAVAILABLE; } - internal_memcpy(buffer, ®s, sizeof(regs)); + buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr)); + internal_memcpy(buffer->data(), ®s, sizeof(regs)); #if defined(__aarch64__) && defined(arm_thread_state64_get_sp) *sp = arm_thread_state64_get_sp(regs); #else @@ -173,9 +174,6 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( return REGISTERS_AVAILABLE; } -uptr SuspendedThreadsListMac::RegisterCount() const { - return MACHINE_THREAD_STATE_COUNT; -} } // namespace __sanitizer #endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) || diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp index 1ed2134..70df31e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp @@ -57,9 +57,9 @@ class SuspendedThreadsListNetBSD : public SuspendedThreadsList { bool ContainsTid(tid_t thread_id) const; void Append(tid_t tid); - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector<uptr> *buffer, uptr *sp) const; - uptr RegisterCount() const; private: InternalMmapVector<tid_t> thread_ids_; @@ -131,7 +131,7 @@ bool ThreadSuspender::SuspendAllThreads() { pl.pl_lwpid = 0; int val; - while ((val = ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 && + while ((val = internal_ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 && pl.pl_lwpid != 0) { suspended_threads_list_.Append(pl.pl_lwpid); VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid, pid_); @@ -335,7 +335,7 @@ void SuspendedThreadsListNetBSD::Append(tid_t tid) { } PtraceRegistersStatus SuspendedThreadsListNetBSD::GetRegistersAndSP( - uptr index, uptr *buffer, uptr *sp) const { + uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { lwpid_t tid = GetThreadID(index); pid_t ppid = internal_getppid(); struct reg regs; @@ -351,14 +351,12 @@ PtraceRegistersStatus SuspendedThreadsListNetBSD::GetRegistersAndSP( } *sp = PTRACE_REG_SP(®s); - internal_memcpy(buffer, ®s, sizeof(regs)); + buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr)); + internal_memcpy(buffer->data(), ®s, sizeof(regs)); return REGISTERS_AVAILABLE; } -uptr SuspendedThreadsListNetBSD::RegisterCount() const { - return sizeof(struct reg) / sizeof(uptr); -} } // namespace __sanitizer #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp index 490c6fe..311d676 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp @@ -12,6 +12,7 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" #include "sanitizer_symbolizer_internal.h" namespace __sanitizer { @@ -258,6 +259,8 @@ class LLVMSymbolizerProcess : public SymbolizerProcess { const char* const kSymbolizerArch = "--default-arch=x86_64"; #elif defined(__i386__) const char* const kSymbolizerArch = "--default-arch=i386"; +#elif SANITIZER_RISCV64 + const char *const kSymbolizerArch = "--default-arch=riscv64"; #elif defined(__aarch64__) const char* const kSymbolizerArch = "--default-arch=arm64"; #elif defined(__arm__) @@ -275,8 +278,8 @@ class LLVMSymbolizerProcess : public SymbolizerProcess { #endif const char *const inline_flag = common_flags()->symbolize_inline_frames - ? "--inlining=true" - : "--inlining=false"; + ? "--inlines" + : "--no-inlines"; int i = 0; argv[i++] = path_to_binary; argv[i++] = inline_flag; diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp index cc23340..f0f1508 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -33,8 +33,15 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { int result = dladdr((const void *)addr, &info); if (!result) return false; - CHECK(addr >= reinterpret_cast<uptr>(info.dli_saddr)); - stack->info.function_offset = addr - reinterpret_cast<uptr>(info.dli_saddr); + // Compute offset if possible. `dladdr()` doesn't always ensure that `addr >= + // sym_addr` so only compute the offset when this holds. Failure to find the + // function offset is not treated as a failure because it might still be + // possible to get the symbol name. + uptr sym_addr = reinterpret_cast<uptr>(info.dli_saddr); + if (addr >= sym_addr) { + stack->info.function_offset = addr - sym_addr; + } + const char *demangled = DemangleSwiftAndCXX(info.dli_sname); if (!demangled) return false; stack->info.function = internal_strdup(demangled); @@ -123,7 +130,7 @@ class AtosSymbolizerProcess : public SymbolizerProcess { argv[i++] = path_to_binary; argv[i++] = "-p"; argv[i++] = &pid_str_[0]; - if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) { + if (GetMacosAlignedVersion() == MacosVersion(10, 9)) { // On Mavericks atos prints a deprecation warning which we suppress by // passing -d. The warning isn't present on other OSX versions, even the // newer ones. @@ -219,10 +226,10 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { start_address = reinterpret_cast<uptr>(info.dli_saddr); } - // Only assig to `function_offset` if we were able to get the function's - // start address. - if (start_address != AddressInfo::kUnknown) { - CHECK(addr >= start_address); + // 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; } return true; diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp index 2963af9..30cba08 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp @@ -83,11 +83,14 @@ void RenderData(InternalScopedString *buffer, const char *format, buffer->append(kFormatData, DI->start); } +bool RenderNeedsSymbolization(const char *format) { return false; } + // We don't support the stack_trace_format flag at all. void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, - const AddressInfo &info, bool vs_style, + uptr address, const AddressInfo *info, bool vs_style, const char *strip_path_prefix, const char *strip_func_prefix) { - buffer->append(kFormatFrame, frame_no, info.address); + CHECK(!RenderNeedsSymbolization(format)); + buffer->append(kFormatFrame, frame_no, address); } Symbolizer *Symbolizer::PlatformInit() { diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index d7b931b..3c379a8 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -78,13 +78,6 @@ static void InitializeSwiftDemangler() { // Attempts to demangle a Swift name. The demangler will return nullptr if a // non-Swift name is passed in. const char *DemangleSwift(const char *name) { - if (!name) return nullptr; - - // Check if we are dealing with a Swift mangled name first. - if (name[0] != '_' || name[1] != 'T') { - return nullptr; - } - if (swift_demangle_f) return swift_demangle_f(name, internal_strlen(name), 0, 0, 0); @@ -321,9 +314,10 @@ class Addr2LinePool : public SymbolizerTool { #if SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, - char *Buffer, int MaxLength); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool +__sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, + char *Buffer, int MaxLength, + bool SymbolizeInlineFrames); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset, char *Buffer, int MaxLength); @@ -346,7 +340,8 @@ class InternalSymbolizer : public SymbolizerTool { bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { bool result = __sanitizer_symbolize_code( - stack->info.module, stack->info.module_offset, buffer_, kBufferSize); + stack->info.module, stack->info.module_offset, buffer_, kBufferSize, + common_flags()->symbolize_inline_frames); if (result) ParseSymbolizePCOutput(buffer_, stack); return result; } diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp index c26724c..06301b8 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp @@ -33,7 +33,8 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info, if (!common_flags()->print_summary) return; InternalScopedString buff(kMaxSummaryLength); buff.append("%s ", error_type); - RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, + RenderFrame(&buff, "%L %F", 0, info.address, &info, + common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix); ReportErrorSummary(buff.data(), alt_tool_name); } @@ -47,14 +48,14 @@ bool ReportFile::SupportsColors() { return SupportsColoredOutput(fd); } -static INLINE bool ReportSupportsColors() { +static inline bool ReportSupportsColors() { return report_file.SupportsColors(); } #else // SANITIZER_FUCHSIA // Fuchsia's logs always go through post-processing that handles colorization. -static INLINE bool ReportSupportsColors() { return true; } +static inline bool ReportSupportsColors() { return true; } #endif // !SANITIZER_FUCHSIA diff --git a/libsanitizer/sanitizer_common/sanitizer_syscall_linux_riscv64.inc b/libsanitizer/sanitizer_common/sanitizer_syscall_linux_riscv64.inc new file mode 100644 index 0000000..89c1260 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_syscall_linux_riscv64.inc @@ -0,0 +1,174 @@ +//===-- sanitizer_syscall_linux_riscv64.inc ---------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implementations of internal_syscall and internal_iserror for Linux/riscv64. +// +//===----------------------------------------------------------------------===// + +// About local register variables: +// https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables +// +// Kernel ABI... +// To my surprise I haven't found much information regarding it. +// Kernel source and internet browsing shows that: +// syscall number is passed in a7 +// (http://man7.org/linux/man-pages/man2/syscall.2.html) results are return in +// a0 and a1 (http://man7.org/linux/man-pages/man2/syscall.2.html) arguments +// are passed in: a0-a7 (see below) +// +// Regarding the arguments. The only "documentation" I could find is +// this comment (!!!) by Bruce Hold on google forums (!!!): +// https://groups.google.com/a/groups.riscv.org/forum/#!topic/sw-dev/exbrzM3GZDQ +// Confirmed by inspecting glibc sources. +// Great way to document things. +#define SYSCALL(name) __NR_##name + +#define INTERNAL_SYSCALL_CLOBBERS "memory" + +static uptr __internal_syscall(u64 nr) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0"); + __asm__ volatile("ecall\n\t" + : "=r"(a0) + : "r"(a7) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall0(n) (__internal_syscall)(n) + +static uptr __internal_syscall(u64 nr, u64 arg1) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall1(n, a1) (__internal_syscall)(n, (u64)(a1)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall2(n, a1, a2) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall3(n, a1, a2, a3) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, + u64 arg4) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall4(n, a1, a2, a3, a4) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4, + long arg5) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + register u64 a4 asm("a4") = arg5; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall5(n, a1, a2, a3, a4, a5) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4, + long arg5, long arg6) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + register u64 a4 asm("a4") = arg5; + register u64 a5 asm("a5") = arg6; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5), (long)(a6)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4, + long arg5, long arg6, long arg7) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + register u64 a4 asm("a4") = arg5; + register u64 a5 asm("a5") = arg6; + register u64 a6 asm("a6") = arg7; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), + "r"(a6) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall7(n, a1, a2, a3, a4, a5, a6, a7) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5), (long)(a6), (long)(a7)) + +#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n +#define __SYSCALL_NARGS(...) \ + __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) +#define __SYSCALL_CONCAT_X(a, b) a##b +#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) +#define __SYSCALL_DISP(b, ...) \ + __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) + +// Helper function used to avoid clobbering of errno. +bool internal_iserror(uptr retval, int *rverrno) { + if (retval >= (uptr)-4095) { + if (rverrno) + *rverrno = -retval; + return true; + } + return false; +} diff --git a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc index 02b7e11..c4a9d99 100644 --- a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc +++ b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc @@ -42,8 +42,8 @@ // DO NOT EDIT! THIS FILE HAS BEEN GENERATED! // // Generated with: generate_netbsd_syscalls.awk -// Generated date: 2019-12-24 -// Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp +// Generated date: 2020-09-10 +// Generated from: syscalls.master,v 1.306 2020/08/14 00:53:16 riastradh Exp // //===----------------------------------------------------------------------===// @@ -872,7 +872,13 @@ PRE_SYSCALL(dup2)(long long from_, long long to_) { /* Nothing to do */ } POST_SYSCALL(dup2)(long long res, long long from_, long long to_) { /* Nothing to do */ } -/* syscall 91 has been skipped */ +PRE_SYSCALL(getrandom)(void *buf_, long long buflen_, long long flags_) { + /* TODO */ +} +POST_SYSCALL(getrandom) +(long long res, void *buf_, long long buflen_, long long flags_) { + /* TODO */ +} PRE_SYSCALL(fcntl)(long long fd_, long long cmd_, void *arg_) { /* Nothing to do */ } @@ -1332,9 +1338,29 @@ PRE_SYSCALL(compat_09_ouname)(void *name_) { /* TODO */ } POST_SYSCALL(compat_09_ouname)(long long res, void *name_) { /* TODO */ } PRE_SYSCALL(sysarch)(long long op_, void *parms_) { /* TODO */ } POST_SYSCALL(sysarch)(long long res, long long op_, void *parms_) { /* TODO */ } -/* syscall 166 has been skipped */ -/* syscall 167 has been skipped */ -/* syscall 168 has been skipped */ +PRE_SYSCALL(__futex) +(void *uaddr_, long long op_, long long val_, void *timeout_, void *uaddr2_, + long long val2_, long long val3_) { + /* TODO */ +} +POST_SYSCALL(__futex) +(long long res, void *uaddr_, long long op_, long long val_, void *timeout_, + void *uaddr2_, long long val2_, long long val3_) { + /* TODO */ +} +PRE_SYSCALL(__futex_set_robust_list)(void *head_, long long len_) { /* TODO */ } +POST_SYSCALL(__futex_set_robust_list) +(long long res, void *head_, long long len_) { + /* TODO */ +} +PRE_SYSCALL(__futex_get_robust_list) +(long long lwpid_, void **headp_, void *lenp_) { + /* TODO */ +} +POST_SYSCALL(__futex_get_robust_list) +(long long res, long long lwpid_, void **headp_, void *lenp_) { + /* TODO */ +} #if !defined(_LP64) PRE_SYSCALL(compat_10_osemsys) (long long which_, long long a2_, long long a3_, long long a4_, long long a5_) { @@ -3824,6 +3850,87 @@ PRE_SYSCALL(__fhstatvfs190) } POST_SYSCALL(__fhstatvfs190) (long long res, void *fhp_, long long fh_size_, void *buf_, long long flags_) {} +PRE_SYSCALL(__acl_get_link)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_get_link) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_set_link)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_set_link) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_delete_link)(void *path_, long long type_) { /* TODO */ } +POST_SYSCALL(__acl_delete_link)(long long res, void *path_, long long type_) { + /* TODO */ +} +PRE_SYSCALL(__acl_aclcheck_link)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_aclcheck_link) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_get_file)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_get_file) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_set_file)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_set_file) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_get_fd)(long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_get_fd) +(long long res, long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_set_fd)(long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_set_fd) +(long long res, long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_delete_file)(void *path_, long long type_) { /* TODO */ } +POST_SYSCALL(__acl_delete_file)(long long res, void *path_, long long type_) { + /* TODO */ +} +PRE_SYSCALL(__acl_delete_fd)(long long filedes_, long long type_) { /* TODO */ } +POST_SYSCALL(__acl_delete_fd) +(long long res, long long filedes_, long long type_) { + /* TODO */ +} +PRE_SYSCALL(__acl_aclcheck_file)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_aclcheck_file) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_aclcheck_fd) +(long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_aclcheck_fd) +(long long res, long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(lpathconf)(void *path_, long long name_) { /* TODO */ } +POST_SYSCALL(lpathconf)(long long res, void *path_, long long name_) { + /* TODO */ +} #undef SYS_MAXSYSARGS } // extern "C" diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp index fca15be..53a537d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp @@ -348,6 +348,22 @@ bool DontDumpShadowMemory(uptr addr, uptr length) { return true; } +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, + UNUSED uptr &high_mem_end) { + const uptr granularity = GetMmapGranularity(); + const uptr alignment = + Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); + const uptr left_padding = + Max<uptr>(granularity, 1ULL << min_shadow_base_alignment); + uptr space_size = shadow_size_bytes + left_padding; + uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, + granularity, nullptr, nullptr); + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + return shadow_start; +} + uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, uptr *largest_gap_found, uptr *max_occupied_addr) { |