Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -261,7 +261,7 @@ ${ARM64} mips mipsel mips64 mips64el) set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} mips64 mips64el ${ARM64}) set(ALL_LSAN_SUPPORTED_ARCH ${X86_64} mips64 mips64el) -set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} mips64 mips64el) +set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} mips64 mips64el ${ARM64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86_64} i386 i686 ${ARM32} mips mips64 mipsel mips64el ${ARM64} powerpc64 powerpc64le) set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} mips64 mips64el ${ARM64}) Index: lib/msan/msan.h =================================================================== --- lib/msan/msan.h +++ lib/msan/msan.h @@ -52,6 +52,47 @@ #define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x4000000000ULL) #define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x002000000000) +#elif SANITIZER_LINUX && defined(__aarch64__) + +# if SANITIZER_AARCH64_VMA == 39 +const MappingDesc kMemoryLayout[] = { + {0x0000000000ULL, 0x4000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x4000000000ULL, 0x4300000000ULL, MappingDesc::SHADOW, "shadow"}, + {0x4300000000ULL, 0x4600000000ULL, MappingDesc::ORIGIN, "origin"}, + {0x4600000000ULL, 0x5500000000ULL, MappingDesc::INVALID, "invalid"}, + {0x5500000000ULL, 0x5600000000ULL, MappingDesc::APP, "app"}, + {0x5600000000ULL, 0x7000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x7000000000ULL, 0x8000000000ULL, MappingDesc::APP, "app"} +}; +// Maps low and high app ranges to contiguous space with zero base: +// Low: 55 0000 0000 - 55 ffff ffff -> 1 0000 0000 - 1 ffff ffff +// High: 70 0000 0000 - 7f ffff ffff -> 0 0000 0000 - f ffff ffff +# define LINEARIZE_MEM(mem) \ + (((uptr)(mem) & ~0x7C00000000ULL) ^ 0x100000000ULL) +# define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x4000000000ULL) +# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x300000000ULL) + +# elif SANITIZER_AARCH64_VMA == 42 +const MappingDesc kMemoryLayout[] = { + {0x00000000000ULL, 0x10000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x10000000000ULL, 0x11b00000000ULL, MappingDesc::SHADOW, "shadow"}, + {0x11b00000000ULL, 0x12000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x12000000000ULL, 0x13b00000000ULL, MappingDesc::ORIGIN, "origin"}, + {0x13b00000000ULL, 0x2aa00000000ULL, MappingDesc::INVALID, "invalid"}, + {0x2aa00000000ULL, 0x2ab00000000ULL, MappingDesc::APP, "app"}, + {0x2ab00000000ULL, 0x3f000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x3f000000000ULL, 0x40000000000ULL, MappingDesc::APP, "app"}, +}; +// Maps low and high app ranges to contigous space with zero base: +// 2 aa00 0000 00 - 2 ab00 0000 00: -> 1a00 0000 00 - 1aff ffff ff +// 3 f000 0000 00 - 4 0000 0000 00: -> 0000 0000 00 - 0fff ffff ff +# define LINEARIZE_MEM(mem) \ + (((uptr)(mem) & ~0x3E000000000ULL) ^ 0x1000000000ULL) +# define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x10000000000ULL) +# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x2000000000ULL) + +# endif // SANITIZER_AARCH64_VMA + #elif SANITIZER_LINUX && defined(__powerpc64__) const MappingDesc kMemoryLayout[] = { Index: lib/msan/msan_allocator.cc =================================================================== --- lib/msan/msan_allocator.cc +++ lib/msan/msan_allocator.cc @@ -67,6 +67,16 @@ typedef SizeClassAllocator64 PrimaryAllocator; +#elif defined(__aarch64__) + static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + static const uptr kRegionSizeLog = 20; + static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; + typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; + typedef CompactSizeClassMap SizeClassMap; + + typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata), + SizeClassMap, kRegionSizeLog, ByteMap, + MsanMapUnmapCallback> PrimaryAllocator; #endif typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator SecondaryAllocator; Index: lib/msan/msan_interceptors.cc =================================================================== --- lib/msan/msan_interceptors.cc +++ lib/msan/msan_interceptors.cc @@ -245,9 +245,15 @@ #if !SANITIZER_FREEBSD // This function actually returns a struct by value, but we can't unpoison a -// temporary! The following is equivalent on all supported platforms, and we -// have a test to confirm that. +// temporary! The following is equivalent on all supported platforms but +// aarch64 (which uses a different register for sret value). We have a test +// to confirm that. INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) { +#ifdef __aarch64__ + uptr r8; + asm volatile("mov %0,x8" : "=r" (r8)); + sret = reinterpret_cast<__sanitizer_mallinfo*>(r8); +#endif REAL(memset)(sret, 0, sizeof(*sret)); __msan_unpoison(sret, sizeof(*sret)); } Index: lib/sanitizer_common/sanitizer_common_syscalls.inc =================================================================== --- lib/sanitizer_common/sanitizer_common_syscalls.inc +++ lib/sanitizer_common/sanitizer_common_syscalls.inc @@ -2301,7 +2301,7 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { #if !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__)) + defined(__powerpc64__) || defined(__aarch64__)) if (data) { if (request == ptrace_setregs) { PRE_READ((void *)data, struct_user_regs_struct_sz); @@ -2322,7 +2322,7 @@ 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(__powerpc64__) || defined(__aarch64__)) if (res >= 0 && data) { // Note that this is different from the interceptor in // sanitizer_common_interceptors.inc. Index: lib/sanitizer_common/sanitizer_platform_interceptors.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_interceptors.h +++ lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -133,7 +133,7 @@ #define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__)) + defined(__powerpc64__) || defined(__aarch64__)) #define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID Index: lib/sanitizer_common/sanitizer_platform_limits_posix.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -724,7 +724,7 @@ #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__)) + defined(__powerpc64__) || defined(__aarch64__)) extern unsigned struct_user_regs_struct_sz; extern unsigned struct_user_fpregs_struct_sz; extern unsigned struct_user_fpxregs_struct_sz; Index: lib/sanitizer_common/sanitizer_platform_limits_posix.cc =================================================================== --- lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -119,7 +119,7 @@ #if SANITIZER_LINUX || SANITIZER_FREEBSD # include # include -# if defined(__mips64) +# if defined(__mips64) || defined(__aarch64__) # include # endif #endif @@ -303,28 +303,42 @@ #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__)) + defined(__powerpc64__) || defined(__aarch64__)) #if defined(__mips64) || defined(__powerpc64__) unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); +#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); #else unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); -#endif // __mips64 || __powerpc64__ -#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) +#endif // __mips64 || __powerpc64__ || __aarch64__ +#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ + defined(__aarch64__) unsigned struct_user_fpxregs_struct_sz = 0; #else unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); -#endif // __x86_64 || __mips64 || __powerpc64__ +#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ int ptrace_peektext = PTRACE_PEEKTEXT; int ptrace_peekdata = PTRACE_PEEKDATA; int ptrace_peekuser = PTRACE_PEEKUSER; +#if defined(PT_GETREGS) && defined(PT_SETREGS) int ptrace_getregs = PTRACE_GETREGS; int ptrace_setregs = PTRACE_SETREGS; +#else + int ptrace_getregs = -1; + int ptrace_setregs = -1; +#endif +#if defined(PT_GETFPREGS) && defined(PT_SETFPREGS) int ptrace_getfpregs = PTRACE_GETFPREGS; int ptrace_setfpregs = PTRACE_SETFPREGS; -#if defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS) +#else + int ptrace_getfpregs = -1; + int ptrace_setfpregs = -1; +#endif +#if defined(PT_GETFPXREGS) && defined(PT_SETFPXREGS) int ptrace_getfpxregs = PTRACE_GETFPXREGS; int ptrace_setfpxregs = PTRACE_SETFPXREGS; #else Index: lib/sanitizer_common/sanitizer_stacktrace.h =================================================================== --- lib/sanitizer_common/sanitizer_stacktrace.h +++ lib/sanitizer_common/sanitizer_stacktrace.h @@ -19,8 +19,7 @@ static const u32 kStackTraceMax = 256; -#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__sparc__) || \ - defined(__mips__)) +#if SANITIZER_LINUX && (defined(__sparc__) || defined(__mips__)) # define SANITIZER_CAN_FAST_UNWIND 0 #elif SANITIZER_WINDOWS # define SANITIZER_CAN_FAST_UNWIND 0 Index: test/msan/chained_origin_limits.cc =================================================================== --- test/msan/chained_origin_limits.cc +++ test/msan/chained_origin_limits.cc @@ -61,6 +61,10 @@ // RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out +// +// AArch64 fails with -fsanitize-memory-track-origins=2 with and invalid access +// on 'return buf[50]'. +// XFAIL: aarch64 #include #include Index: test/msan/dlerror.cc =================================================================== --- test/msan/dlerror.cc +++ test/msan/dlerror.cc @@ -1,4 +1,8 @@ // RUN: %clangxx_msan -O0 %s -o %t && %run %t +// +// AArch64 shows fails with uninitialized bytes in __interceptor_strcmp from +// dlfcn/dlerror.c:107 (glibc). +// XFAIL: aarch64 #include #include Index: test/msan/mmap.cc =================================================================== --- test/msan/mmap.cc +++ test/msan/mmap.cc @@ -7,6 +7,8 @@ #include #include #include +#include +#include "test.h" bool AddrIsApp(void *p) { uintptr_t addr = (uintptr_t)p; @@ -18,12 +20,24 @@ return addr >= 0x00e000000000ULL; #elif defined(__powerpc64__) return addr < 0x000100000000ULL || addr >= 0x300000000000ULL; +#elif defined(__aarch64__) + unsigned long vma = SystemVMA(); + if (vma == 39) + return (addr >= 0x5500000000ULL && addr < 0x5600000000ULL) || + (addr > 0x7000000000ULL); + else if (vma == 42) + return (addr >= 0x2aa00000000ULL && addr < 0x2ab00000000ULL) || + (addr > 0x3f000000000ULL); + else { + fprintf(stderr, "unsupported vma: %lu\n", vma); + exit(1); + } #endif } int main() { // Large enough to quickly exhaust the entire address space. -#if defined(__mips64) +#if defined(__mips64) || defined(__aarch64__) const size_t kMapSize = 0x100000000ULL; #else const size_t kMapSize = 0x1000000000ULL; Index: test/msan/mmap_below_shadow.cc =================================================================== --- test/msan/mmap_below_shadow.cc +++ test/msan/mmap_below_shadow.cc @@ -27,6 +27,9 @@ #elif defined (__powerpc64__) uintptr_t hint = 0x2f0000000000ULL; const uintptr_t app_start = 0x300000000000ULL; +#elif defined (__aarch64__) + uintptr_t hint = 0x4f0000000ULL; + const uintptr_t app_start = 0x7000000000ULL; #endif uintptr_t p = (uintptr_t)mmap( (void *)hint, 4096, PROT_WRITE, Index: test/msan/param_tls_limit.cc =================================================================== --- test/msan/param_tls_limit.cc +++ test/msan/param_tls_limit.cc @@ -4,6 +4,10 @@ // RUN: %clangxx_msan -O0 %s -o %t && %run %t // RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && %run %t // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 %s -o %t && %run %t +// +// AArch64 fails with: +// void f801(S<801>): Assertion `__msan_test_shadow(&s, sizeof(s)) == -1' failed +// XFAIL: aarch64 #include #include Index: test/msan/signal_stress_test.cc =================================================================== --- test/msan/signal_stress_test.cc +++ test/msan/signal_stress_test.cc @@ -1,4 +1,7 @@ // RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %run %t +// +// AArch64 lacks var args instrumentation. +// XFAIL: aarch64 // Test that va_arg shadow from a signal handler does not leak outside. Index: test/msan/strlen_of_shadow.cc =================================================================== --- test/msan/strlen_of_shadow.cc +++ test/msan/strlen_of_shadow.cc @@ -7,6 +7,8 @@ #include #include #include +#include +#include "test.h" const char *mem_to_shadow(const char *p) { #if defined(__x86_64__) @@ -17,6 +19,22 @@ #define LINEARIZE_MEM(mem) \ (((uintptr_t)(mem) & ~0x200000000000ULL) ^ 0x100000000000ULL) return (char *)(LINEARIZE_MEM(p) + 0x080000000000ULL); +#elif defined(__aarch64__) + unsigned long vma = SystemVMA(); + +#define LINEARIZE_MEM_39(mem) \ + (((uintptr_t)(mem) & ~0x7C00000000ULL) ^ 0x100000000ULL) +#define LINEARIZE_MEM_42(mem) \ + (((uintptr_t)(mem) & ~0x3E000000000ULL) ^ 0x1000000000ULL) + + if (vma == 39) + return (char *)(LINEARIZE_MEM_39(p) + 0x4000000000ULL); + else if (vma == 42) + return (char *)(LINEARIZE_MEM_42(p) + 0x10000000000ULL); + else { + fprintf(stderr, "unsupported vma: %lu\n", vma); + exit(1); + } #endif } Index: test/msan/test.h =================================================================== --- /dev/null +++ test/msan/test.h @@ -0,0 +1,15 @@ +#if __LP64__ +# define SANITIZER_WORDSIZE 64 +#else +# define SANITIZER_WORDSIZE 32 +#endif + +// This is a simplified version of GetMaxVirtualAddress function. +unsigned long SystemVMA () { +#if SANITIZER_WORDSIZE == 64 + unsigned long vma = (unsigned long)__builtin_frame_address(0); + return SANITIZER_WORDSIZE - __builtin_clzll(vma); +#else + return SANITIZER_WORDSIZE; +#endif +} Index: test/sanitizer_common/TestCases/Linux/ptrace.cc =================================================================== --- test/sanitizer_common/TestCases/Linux/ptrace.cc +++ test/sanitizer_common/TestCases/Linux/ptrace.cc @@ -7,11 +7,17 @@ #include #include #include +#include #include +#include #if __mips64 #include #include #endif +#ifdef __aarch64__ +// GLIBC 2.20+ sys/user does not include asm/ptrace.h + #include +#endif int main(void) { pid_t pid; @@ -55,6 +61,26 @@ printf("%lx\n", (elf_greg_t)fpregs[32]); #endif // (__powerpc64__ || __mips64) +#if (__aarch64__) + struct iovec regset_io; + + struct user_pt_regs regs; + regset_io.iov_base = ®s; + regset_io.iov_len = sizeof(regs); + res = ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, (void*)®set_io); + assert(!res); + if (regs.pc) + printf("%llx\n", regs.pc); + + struct user_fpsimd_state fpregs; + regset_io.iov_base = &fpregs; + regset_io.iov_len = sizeof(fpregs); + res = ptrace(PTRACE_GETREGSET, pid, (void*)NT_FPREGSET, (void*)®set_io); + assert(!res); + if (fpregs.fpsr) + printf("%x\n", fpregs.fpsr); +#endif // (__aarch64__) + siginfo_t siginfo; res = ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo); assert(!res); Index: test/ubsan/TestCases/Misc/nonnull-arg.cpp =================================================================== --- test/ubsan/TestCases/Misc/nonnull-arg.cpp +++ test/ubsan/TestCases/Misc/nonnull-arg.cpp @@ -7,6 +7,9 @@ // RUN: not %run %t 0m 2>&1 | FileCheck %s --check-prefix=METHOD // RUN: not %run %t 0f 2>&1 | FileCheck %s --check-prefix=FUNC // RUN: not %run %t 0v 2>&1 | FileCheck %s --check-prefix=VARIADIC +// +// AArch64 lacks var args instrumentation. +// XFAIL: aarch64 class C { int *null_; @@ -40,19 +43,19 @@ case 'c': return C(0x0, arg).value(); // CTOR: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:21: runtime error: null pointer passed as argument 2, which is declared to never be null - // CTOR-NEXT: {{.*}}nonnull-arg.cpp:16:31: note: nonnull attribute specified here + // CTOR-NEXT: {{.*}}nonnull-arg.cpp:19:31: note: nonnull attribute specified here case 'm': return C(0x0, &local).method(arg, 0x0); // METHOD: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:36: runtime error: null pointer passed as argument 1, which is declared to never be null - // METHOD-NEXT: {{.*}}nonnull-arg.cpp:19:54: note: nonnull attribute specified here + // METHOD-NEXT: {{.*}}nonnull-arg.cpp:22:54: note: nonnull attribute specified here case 'f': return func(arg); // FUNC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:19: runtime error: null pointer passed as argument 1, which is declared to never be null - // FUNC-NEXT: {{.*}}nonnull-arg.cpp:24:16: note: nonnull attribute specified here + // FUNC-NEXT: {{.*}}nonnull-arg.cpp:27:16: note: nonnull attribute specified here case 'v': return variadic(42, arg); // VARIADIC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:27: runtime error: null pointer passed as argument 2, which is declared to never be null - // VARIADIC-NEXT: {{.*}}nonnull-arg.cpp:27:16: note: nonnull attribute specified here + // VARIADIC-NEXT: {{.*}}nonnull-arg.cpp:30:16: note: nonnull attribute specified here } return 0; }