Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -1,3 +1,7 @@ +if(${COMPILER_RT_CROSS_COMPILING_NOANDROID}) +SET(ANDROID "0" CACHE STRING "ANDROID" FORCE) +endif() + # CMake build for CompilerRT. # # This build assumes that CompilerRT is checked out into the Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -158,7 +158,15 @@ detect_target_arch() set(COMPILER_RT_OS_SUFFIX "-android") else() - if("${LLVM_NATIVE_ARCH}" STREQUAL "X86") + # See If the user wants cross compiling, e.g. using clang for something + # other than android. + # This is useful if we want to use CMAKE_C_FLAGS and CMAKE_C_COMPILER to + # pass in cross compilation args, i.e. we are using a single version of clang + # that has a default target other than the host to generate compiler-rt for the + # host (or some other platform) + if(${COMPILER_RT_CROSS_COMPILING}) + detect_target_arch() + elseif("${LLVM_NATIVE_ARCH}" STREQUAL "X86") if(NOT MSVC) test_target_arch(x86_64 "" "-m64") # FIXME: We build runtimes for both i686 and i386, as "clang -m32" may @@ -222,7 +230,7 @@ filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH x86_64 i386 i686 powerpc64 powerpc64le arm aarch64 mips mips64 mipsel mips64el) filter_available_targets(ASAN_SUPPORTED_ARCH - x86_64 i386 i686 powerpc64 powerpc64le arm mips mipsel mips64 mips64el) + x86_64 i386 i686 powerpc64 powerpc64le arm aarch64 mips mipsel mips64 mips64el) filter_available_targets(DFSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) filter_available_targets(LSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) # LSan common files should be available on all architectures supported @@ -232,7 +240,11 @@ filter_available_targets(MSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 i686 arm mips mips64 mipsel mips64el aarch64 powerpc64 powerpc64le) +if(${COMPILER_RT_FORCE_TSAN_AARCH64}) +filter_available_targets(TSAN_SUPPORTED_ARCH x86_64 mips64 mips64el aarch64) +else() filter_available_targets(TSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) +endif() filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips mipsel mips64 mips64el) if(ANDROID) @@ -299,7 +311,7 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|FreeBSD") + OS_NAME MATCHES "Linux|FreeBSD|Android") set(COMPILER_RT_HAS_TSAN TRUE) else() set(COMPILER_RT_HAS_TSAN FALSE) Index: lib/sanitizer_common/sanitizer_libc.h =================================================================== --- lib/sanitizer_common/sanitizer_libc.h +++ lib/sanitizer_common/sanitizer_libc.h @@ -95,6 +95,9 @@ uptr internal_getpid(); uptr internal_getppid(); +void *internal_malloc(uptr s); +void *internal_calloc(uptr s, uptr n); + int internal_fork(); // Threading Index: lib/sanitizer_common/sanitizer_libc.cc =================================================================== --- lib/sanitizer_common/sanitizer_libc.cc +++ lib/sanitizer_common/sanitizer_libc.cc @@ -71,6 +71,19 @@ return dest; } +void *internal_malloc(uptr n) { + return InternalAlloc(n); +} + +void *internal_calloc(uptr n, uptr s) { + void *rtn = InternalAlloc(n * s); + if (rtn) { + internal_memset(rtn, 0, n * s); + } + return (void*)0; +} + + // Semi-fast bzero for 16-aligned data. Still far from peak performance. void internal_bzero_aligned16(void *s, uptr n) { struct S16 { u64 a, b; } ALIGNED(16); Index: lib/sanitizer_common/sanitizer_linux.h =================================================================== --- lib/sanitizer_common/sanitizer_linux.h +++ lib/sanitizer_common/sanitizer_linux.h @@ -43,7 +43,7 @@ // 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__) +#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -870,6 +870,12 @@ return clone(fn, child_stack, flags, arg, parent_tidptr, newtls, child_tidptr); } +#elif defined(__aarch64__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + return clone(fn, child_stack, flags, arg, parent_tidptr, + newtls, child_tidptr); +} #endif // defined(__x86_64__) && SANITIZER_LINUX #if SANITIZER_ANDROID @@ -902,7 +908,8 @@ void GetExtraActivationFlags(char *buf, uptr size) { CHECK(size > PROP_VALUE_MAX); - __system_property_get("asan.options", buf); + // fixme: below not available in android L and onwards + //__system_property_get("asan.options", buf); } #endif Index: lib/sanitizer_common/sanitizer_platform_interceptors.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_interceptors.h +++ lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -153,12 +153,12 @@ #define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WORDEXP \ - SI_FREEBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGSETOPS \ - SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID + (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || __aarch64__) #define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_BACKTRACE 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 @@ -321,7 +321,8 @@ long pw_change; char *pw_class; #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID || (SANITIZER_ANDROID && __aarch64__) + // this is defined in aarch64 char *pw_gecos; #endif char *pw_dir; @@ -383,7 +384,7 @@ }; #endif -#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD +#if SANITIZER_MAC || SANITIZER_FREEBSD struct __sanitizer_msghdr { void *msg_name; unsigned msg_namelen; @@ -398,6 +399,23 @@ int cmsg_level; int cmsg_type; }; +#elif SANITIZER_ANDROID +struct __sanitizer_msghdr { + void* msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec* msg_iov; + unsigned long msg_iovlen; + void* msg_control; + unsigned long msg_controllen; + int msg_flags; +}; + +struct __sanitizer_cmsghdr { + unsigned long cmsg_len; + int cmsg_level; + int cmsg_type; +}; + #else struct __sanitizer_msghdr { void *msg_name; @@ -519,6 +537,18 @@ }; #endif +#if SANITIZER_ANDROID && __aarch64__ + struct __sanitizer_sigaction { + unsigned int sa_flags; + union { + void (*handler)(int); + void (*sigaction)(int, void*, void*); + }; + __sanitizer_sigset_t sa_mask; + void (*sa_restorer)(void); + }; + +#else // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. struct __sanitizer_sigaction { #if defined(__mips__) && !SANITIZER_FREEBSD @@ -544,6 +574,7 @@ int sa_resv[1]; #endif }; +#endif #if SANITIZER_FREEBSD typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; @@ -693,6 +724,57 @@ int _fileno; }; # define SANITIZER_HAS_STRUCT_FILE 1 +#elif SANITIZER_ANDROID +#if defined(__LP64__) + struct __sanitizer__sbuf { + unsigned char* _base; + uptr _size; +}; +#else + struct __sanitizer__sbuf { + unsigned char *_base; + int _size; + }; +#endif + + struct __sanitizer_FILE { + unsigned char *_p; /* current position in (some) buffer */ + int _r; /* read space left for getc() */ + int _w; /* write space left for putc() */ +#if defined(__LP64__) + int _flags; /* flags, below; this FILE is free if 0 */ + int _file; /* fileno, if Unix descriptor, else -1 */ +#else + short _flags; /* flags, below; this FILE is free if 0 */ + short _file; /* fileno, if Unix descriptor, else -1 */ +#endif + /* the buffer (at least 1 byte, if !NULL) */ + struct __sanitizer__sbuf _bf; + int _lbfsize; /* 0 or -_bf._size, for inline putc */ + + /* operations */ + void *_cookie; /* cookie passed to io functions */ + int (*_close)(void *); + int (*_read)(void *, char *, int); + uptr (*_seek)(void *, uptr, int); + int (*_write)(void *, const char *, int); + + /* extension data, to avoid further ABI breakage */ + struct __sanitizer__sbuf _ext; + /* data for long sequences of ungetc() */ + unsigned char *_up; /* saved _p when _p is doing ungetc data */ + int _ur; /* saved _r when _r is counting ungetc data */ + + unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */ + unsigned char _nbuf[1]; /* guarantee a getc() buffer */ + + struct __sanitizer__sbuf _lb; /* buffer for fgetln() */ + + /* Unix stdio files get aligned to block boundaries on fseek() */ + int _blksize; /* stat.st_blksize (may be != _bf._size) */ + uptr _offset; /* current lseek offset */ + }; +# define SANITIZER_HAS_STRUCT_FILE 0 #else typedef void __sanitizer_FILE; # define SANITIZER_HAS_STRUCT_FILE 0 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 @@ -164,6 +164,7 @@ #include #include #include +#include #endif #if SANITIZER_LINUX @@ -1142,7 +1143,7 @@ CHECK_SIZE_AND_OFFSET(passwd, pw_dir); CHECK_SIZE_AND_OFFSET(passwd, pw_shell); -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID || (SANITIZER_ANDROID && __aarch64__) CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); #endif Index: lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)) +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || defined(__aarch64__)) #include "sanitizer_stoptheworld.h" @@ -469,6 +469,9 @@ typedef struct user regs_struct; #define REG_SP regs[EF_REG29] +#elif defined(__aarch64__) +typedef struct user_pt_regs regs_struct; +#define REG_SP sp #else #error "Unsupported architecture" #endif // SANITIZER_ANDROID && defined(__arm__) @@ -479,7 +482,7 @@ pid_t tid = GetThreadID(index); regs_struct regs; int pterrno; - if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, ®s), + if (internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, NULL, ®s), &pterrno)) { VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, pterrno); Index: lib/tsan/CMakeLists.txt =================================================================== --- lib/tsan/CMakeLists.txt +++ lib/tsan/CMakeLists.txt @@ -17,6 +17,7 @@ # FIXME: Add support for --sysroot=. compile flag: set(TSAN_SOURCES + rtl/tsan_aarch64_tls_workaround.cc rtl/tsan_clock.cc rtl/tsan_flags.cc rtl/tsan_fd.cc @@ -50,6 +51,7 @@ endif() set(TSAN_HEADERS + rtl/tsan_aarch64_tls_workaround.h rtl/tsan_clock.h rtl/tsan_defs.h rtl/tsan_dense_alloc.h Index: lib/tsan/rtl/tsan.syms.extra =================================================================== --- lib/tsan/rtl/tsan.syms.extra +++ lib/tsan/rtl/tsan.syms.extra @@ -8,6 +8,7 @@ __tsan_unaligned* __tsan_release __tsan_acquire +InitTSanWorkAround Annotate* WTFAnnotate* RunningOnValgrind Index: lib/tsan/rtl/tsan_aarch64_tls_workaround.h =================================================================== --- /dev/null +++ lib/tsan/rtl/tsan_aarch64_tls_workaround.h @@ -0,0 +1,42 @@ +//===-- tsan_android_aarch64_tls_workaround.h -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer (TSan), a race detector. +// +// This file presents some macros +//===----------------------------------------------------------------------===// + +#ifndef TSAN_AARCH64_TLS_WORKAROUND_H +#define TSAN_AARCH64_TLS_WORKAROUND_H + +// This file implements a few macros +// For OSs that properly implement __thread, this will devolve to a no-op. +// For others (notably Android on AArch64), we get around the lack of support +// via using pthread calls internally to implement it. +#include "sanitizer_common/sanitizer_platform.h" + +namespace __tsan { +extern "C" bool InitTSanWorkAround(); +}; + +#if defined(__aarch64__) +#define SANITIZER_TLS_WORKAROUND_NEEDED 1 +#define GetFromTLS(tlsvar) get_from_tls_##tlsvar() + +// Due to chicken-vs-egg decl issues, these are the real accessor functions +// these accessor functions are defined elsewhere +// char &get_from_tls_cur_thread_placeholder() (used in tsan_rtl.cc) +// __sanitizer_sigset_t &get_from_tls_emptset() (used in tsan_interceptors.cc) +// __sanitizer_sigset_t &get_from_tls_oldset(); + +#else +#define GetFromTLS(tlsvar) tlsvar +#endif + +#endif Index: lib/tsan/rtl/tsan_aarch64_tls_workaround.cc =================================================================== --- /dev/null +++ lib/tsan/rtl/tsan_aarch64_tls_workaround.cc @@ -0,0 +1,95 @@ +#include + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_platform_limits_posix.h" +#include "sanitizer_common/sanitizer_placement_new.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "interception/interception.h" + +#include "tsan_interface.h" +#include "tsan_platform.h" +#include "tsan_rtl.h" +#include "interception/interception.h" +#include + + +extern "C" { + int pthread_key_create(unsigned *key, void (*destructor)(void* v)); + void *pthread_getspecific(unsigned key); + int pthread_setspecific(unsigned key, const void *v); +}; + +using namespace __tsan; + +// This needs to be aligned(64) +struct TSanTLSHack { + uptr tid; + char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64); + __sanitizer_sigset_t emptyset, oldset; +}; + +static const int PrimeNumber = 2053; +static TSanTLSHack* TLSHack[PrimeNumber]; +static int Count = 0; + +DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *dst, int v, uptr size); +DECLARE_REAL_AND_INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size); +DECLARE_REAL_AND_INTERCEPTOR(int, memcmp, const void *dst, const void *src, uptr size); +// uhoh dlsym() uses these too! +DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size); +DECLARE_REAL_AND_INTERCEPTOR(void *, calloc, uptr nmeb, uptr size); + +namespace __tsan { + +static bool TSanTLSWorkAroundHasInited=0; + +void InitTLSHack() { + internal_memset(TLSHack, 0, sizeof(TLSHack)); + Count = 0; +} + +bool InitTSanWorkAround() { + // We need to setup it early, because functions like dlsym() can call it. + REAL(memset) = internal_memset; + REAL(memcpy) = internal_memcpy; + REAL(memcmp) = internal_memcmp; + REAL(malloc) = internal_malloc; + REAL(calloc) = internal_calloc; + if (TSanTLSWorkAroundHasInited == 0) + InitTLSHack(); + TSanTLSWorkAroundHasInited = 1; + return TSanTLSWorkAroundHasInited; +} + +extern +TSanTLSHack *GetTSanTLSHack() { + CHECK_EQ(TSanTLSWorkAroundHasInited, 1); + uptr tid = GetThreadSelf(); + uptr hash = tid % PrimeNumber; + + if (TLSHack[hash] == 0ll) { + TLSHack[hash] = (TSanTLSHack*)InternalAlloc(sizeof(TSanTLSHack)); + TLSHack[hash]->tid = tid; + DPrintf("Thread %p at slot %p getting ThreadState %p\n", + tid, hash, &(TLSHack[hash]->cur_thread_placeholder[0])); + return TLSHack[hash]; + } + CHECK_EQ(TLSHack[hash]->tid, tid); + return TLSHack[hash]; +} + +char &get_from_tls_cur_thread_placeholder() { + return GetTSanTLSHack()->cur_thread_placeholder[0]; +}; + +__sanitizer_sigset_t &get_from_tls_emptyset() { + return GetTSanTLSHack()->emptyset; +}; + +__sanitizer_sigset_t &get_from_tls_oldset() { + return GetTSanTLSHack()->oldset; +}; + +} Index: lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors.cc +++ lib/tsan/rtl/tsan_interceptors.cc @@ -13,6 +13,8 @@ // sanitizer_common/sanitizer_common_interceptors.inc //===----------------------------------------------------------------------===// +static unsigned long long GLOBAL_interceptor_count = 0; + #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_linux.h" @@ -39,6 +41,11 @@ #define stderr __stderrp #endif +#if SANITIZER_ANDROID +#define __errno_location __errno +#define fileno_unlocked fileno +#endif + #ifdef __mips__ const int kSigCount = 129; #else @@ -68,7 +75,9 @@ extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v)); extern "C" int pthread_setspecific(unsigned key, const void *v); DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *) +#if !SANITIZER_ANDROID extern "C" int pthread_yield(); +#endif extern "C" int pthread_sigmask(int how, const __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset); // REAL(sigfillset) defined in common interceptors. @@ -76,17 +85,43 @@ DECLARE_REAL(int, fflush, __sanitizer_FILE *fp) extern "C" void *pthread_self(); extern "C" void _exit(int status); + extern "C" int *__errno_location(); extern "C" int fileno_unlocked(void *stream); + +#if SANITIZER_ANDROID && __aarch64__ +// bionic does not have __libc_(malloc/realloc/calloc/free) +DECLARE_REAL(void *, malloc, uptr); +DECLARE_REAL(void *, calloc, uptr, uptr); +DECLARE_REAL(void *, realloc, void *, uptr); +DECLARE_REAL(void, free, void *); + +#define __libc_malloc REAL(malloc) +#define __libc_realloc REAL(realloc) +#define __libc_calloc REAL(calloc) +#define __libc_free REAL(free) +#else extern "C" void *__libc_malloc(uptr size); +extern "C" void __libc_free(void *ptr); extern "C" void *__libc_calloc(uptr size, uptr n); extern "C" void *__libc_realloc(void *ptr, uptr size); -extern "C" void __libc_free(void *ptr); +#endif + + extern "C" int dirfd(void *dirp); #if !SANITIZER_FREEBSD extern "C" int mallopt(int param, int value); #endif + +#if SANITIZER_ANDROID +extern __sanitizer_FILE __sF[]; +#define stdout (&__sF[1]) +#define stderr (&__sF[2]) +#else extern __sanitizer_FILE *stdout, *stderr; +#endif // SANITIZER_ANDROID + + const int PTHREAD_MUTEX_RECURSIVE = 1; const int PTHREAD_MUTEX_RECURSIVE_NP = 1; const int EINVAL = 22; @@ -117,7 +152,7 @@ # define F_TLOCK 2 /* Test and lock a region for exclusive use. */ # define F_TEST 3 /* Test a region for other processes locks. */ -#define errno (*__errno_location()) +#define get_errno_lval (*__errno_location()) typedef void (*sighandler_t)(int sig); typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx); @@ -249,8 +284,10 @@ } #define SCOPED_INTERCEPTOR_RAW(func, ...) \ + ++GLOBAL_interceptor_count; \ ThreadState *thr = cur_thread(); \ const uptr caller_pc = GET_CALLER_PC(); \ + DPrintf2("INTERCEPT: " #func " %s:%d:%s\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); \ ScopedInterceptor si(thr, #func, caller_pc); \ const uptr pc = StackTrace::GetCurrentPc(); \ (void)pc; \ @@ -540,7 +577,11 @@ TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) { if (cur_thread()->in_symbolizer) +#if SANITIZER_ANDROID + return REAL(calloc)(size, n); +#else return __libc_calloc(size, n); +#endif void *p = 0; { SCOPED_INTERCEPTOR_RAW(calloc, size, n); @@ -552,7 +593,12 @@ TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) { if (cur_thread()->in_symbolizer) +#if SANITIZER_ANDROID + return REAL(realloc)(p, size); +#else return __libc_realloc(p, size); +#endif + if (p) invoke_free_hook(p); { @@ -757,7 +803,7 @@ if (*addr) { if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) { if (flags & MAP_FIXED) { - errno = EINVAL; + get_errno_lval = EINVAL; return false; } else { *addr = 0; @@ -917,7 +963,7 @@ } ThreadIgnoreEnd(thr, 0); while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) - pthread_yield(); + internal_sched_yield(); atomic_store(&p->tid, 0, memory_order_release); ThreadStart(thr, tid, GetTid()); } @@ -969,7 +1015,7 @@ CHECK_NE(tid, 0); atomic_store(&p.tid, tid, memory_order_release); while (atomic_load(&p.tid, memory_order_acquire) != 0) - pthread_yield(); + internal_sched_yield(); } if (attr == &myattr) pthread_attr_destroy(&myattr); @@ -1322,7 +1368,7 @@ atomic_store(a, 2, memory_order_release); } else { while (v != 2) { - pthread_yield(); + internal_sched_yield(); v = atomic_load(a, memory_order_acquire); } if (!thr->in_ignored_lib) @@ -1466,7 +1512,7 @@ #define TSAN_MAYBE_INTERCEPT_LSTAT64 #endif -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && ! SANITIZER_ANDROID TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) { SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf); if (fd > 0) @@ -1479,7 +1525,9 @@ #endif TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) { -#if SANITIZER_FREEBSD +// SANITIZER_TLS_WORKAROUND_NEEDED is for ANDROID&&__aarch64__ +// ANDROID does not have fxstat and friends +#if SANITIZER_FREEBSD||SANITIZER_TLS_WORKAROUND_NEEDED SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf); if (fd > 0) FdAccess(thr, pc, fd); @@ -1492,7 +1540,7 @@ #endif } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD&&!SANITIZER_TLS_WORKAROUND_NEEDED TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) { SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf); if (fd > 0) @@ -1504,7 +1552,7 @@ #define TSAN_MAYBE_INTERCEPT___FXSTAT64 #endif -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD&&!SANITIZER_TLS_WORKAROUND_NEEDED TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) { SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf); if (fd > 0) @@ -1513,8 +1561,18 @@ } #define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64) #else +#if SANITIZER_TLS_WORKAROUND_NEEDED +TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) { + SCOPED_TSAN_INTERCEPTOR(fstat64, fd, buf); + if (fd > 0) + FdAccess(thr, pc, fd); + return REAL(fstat64)(fd, buf); +} +#define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64) +#else #define TSAN_MAYBE_INTERCEPT_FSTAT64 #endif +#endif TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) { SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode); @@ -1910,8 +1968,8 @@ if (acquire) Acquire(thr, 0, (uptr)&sigactions[sig]); // Ensure that the handler does not spoil errno. - const int saved_errno = errno; - errno = 99; + const int saved_errno = get_errno_lval; + get_errno_lval = 99; // This code races with sigaction. Be careful to not read sa_sigaction twice. // Also need to remember pc for reporting before the call, // because the handler can reset it. @@ -1931,7 +1989,7 @@ // because in async signal processing case (when handler is called directly // from rtl_generic_sighandler) we have not yet received the reraised // signal; and it looks too fragile to intercept all ways to reraise a signal. - if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) { + if (flags()->report_bugs && !sync && sig != SIGTERM && get_errno_lval != 99) { VarSizeStackTrace stack; // StackTrace::GetNestInstructionPc(pc) is used because return address is // expected, OutputReport() will undo this. @@ -1943,7 +2001,7 @@ OutputReport(thr, rep); } } - errno = saved_errno; + get_errno_lval = saved_errno; } void ProcessPendingSignals(ThreadState *thr) { @@ -1953,10 +2011,22 @@ return; atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed); atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); +#if SANITIZER_TLS_WORKAROUND_NEEDED + extern __sanitizer_sigset_t &get_from_tls_emptyset(); + extern __sanitizer_sigset_t &get_from_tls_oldset(); + extern void internal_sigfillset(__sanitizer_sigset_t *); + // +#else // These are too big for stack. static THREADLOCAL __sanitizer_sigset_t emptyset, oldset; - CHECK_EQ(0, REAL(sigfillset)(&emptyset)); - CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &emptyset, &oldset)); +#endif + __sanitizer_sigset_t *P = & GetFromTLS(emptyset); + CHECK_EQ(0, REAL(sigfillset)(P)); + __sanitizer_sigset_t *E = &GetFromTLS(emptyset); + __sanitizer_sigset_t *O = &GetFromTLS(oldset); + + CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, E, O)); + for (int sig = 0; sig < kSigCount; sig++) { SignalDesc *signal = &sctx->pending_signals[sig]; if (signal->armed) { @@ -1965,7 +2035,7 @@ &signal->siginfo, &signal->ctx); } } - CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &oldset, 0)); + CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &GetFromTLS(oldset), 0)); atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); } @@ -2455,7 +2525,7 @@ REAL(memcmp) = internal_memcmp; // Instruct libc malloc to consume less memory. -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID mallopt(1, 0); // M_MXFAST mallopt(-3, 32*1024); // M_MMAP_THRESHOLD #endif @@ -2634,3 +2704,4 @@ } } // namespace __tsan + Index: lib/tsan/rtl/tsan_interface.h =================================================================== --- lib/tsan/rtl/tsan_interface.h +++ lib/tsan/rtl/tsan_interface.h @@ -63,6 +63,8 @@ SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write_range(void *addr, unsigned long size); // NOLINT + + #ifdef __cplusplus } // extern "C" #endif Index: lib/tsan/rtl/tsan_interface.cc =================================================================== --- lib/tsan/rtl/tsan_interface.cc +++ lib/tsan/rtl/tsan_interface.cc @@ -23,11 +23,23 @@ typedef u16 uint16_t; typedef u32 uint32_t; typedef u64 uint64_t; +static u64 __tsan_init_count=0; void __tsan_init() { + __tsan_init_count++; +#if SANITIZER_TLS_WORKAROUND_NEEDED + bool C = InitTSanWorkAround(); (void)C; + DPrintf("__tsan_init called %lld times -- InitTSanWorkAround() == %d\n", + __tsan_init_count, C); +#endif Initialize(cur_thread()); } +#if SANITIZER_TLS_WORKAROUND_NEEDED +__attribute__((section(".preinit_array"), used)) +void (*__local_tsan_preinitc)(void) = __tsan_init; +#endif // SANITIZER_TLS_WORKAROUND_NEEDED + void __tsan_read16(void *addr) { MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8); MemoryRead(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8); Index: lib/tsan/rtl/tsan_platform.h =================================================================== --- lib/tsan/rtl/tsan_platform.h +++ lib/tsan/rtl/tsan_platform.h @@ -14,7 +14,7 @@ #ifndef TSAN_PLATFORM_H #define TSAN_PLATFORM_H - +// #define TSAN_DEBUG_OUTPUT 2 #if !defined(__LP64__) && !defined(_WIN64) # error "Only 64-bit is supported" #endif @@ -88,6 +88,32 @@ const uptr kVdsoBeg = 0xfffff00000ull; #endif +#if defined(__aarch64__) +/* +// aarch64: -- memory maps are wierd here. +*/ +#if !defined(__ANDROID__) +#error "please fix for aarch64 !ANDROID" +#endif + +const uptr kShadowBeg = 0x1400000000ull; +const uptr kShadowEnd = 0x2400000000ull; +const uptr kMetaShadowBeg = 0x3000000000ull; +const uptr kMetaShadowEnd = 0x4000000000ull; +const uptr kLoAppMemBeg = 0x5500000000ull; +const uptr kLoAppMemEnd = 0x5600000000ull; +const uptr kTraceMemBeg = 0x6000000000ull; +const uptr kTraceMemEnd = 0x6200000000ull; +const uptr kHeapMemBeg = 0x7e00000000ull; +const uptr kHeapMemEnd = 0x7f00000000ull; +const uptr kHiAppMemBeg = 0x7f00000000ull; +const uptr kHiAppMemEnd = 0x8000000000ull; +const uptr kAppMemMsk = 0xfc00000000ull; +const uptr kAppMemMskRtn = 0x7c00000000ull; +const uptr kAppMemXor = 0x0400000000ull; +const uptr kVdsoBeg = 0xf000000000ull; +#endif + ALWAYS_INLINE bool IsAppMem(uptr mem) { return (mem >= kHeapMemBeg && mem < kHeapMemEnd) || @@ -119,6 +145,16 @@ ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg); } +#if defined(__aarch64__) +ALWAYS_INLINE +uptr ShadowToMem(uptr s) { + CHECK(IsShadowMem(s)); + if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1)) + return (s / kShadowCnt) ^ kAppMemXor | kLoAppMemBeg; + else + return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMskRtn; +} +#else // __mips64 and __x86_64__ ALWAYS_INLINE uptr ShadowToMem(uptr s) { CHECK(IsShadowMem(s)); @@ -127,6 +163,7 @@ else return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk; } +#endif static USED uptr UserRegions[] = { kLoAppMemBeg, kLoAppMemEnd, Index: lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- lib/tsan/rtl/tsan_platform_linux.cc +++ lib/tsan/rtl/tsan_platform_linux.cc @@ -220,6 +220,9 @@ #elif defined(__mips64) const uptr kMadviseRangeBeg = 0xff00000000ull; const uptr kMadviseRangeSize = 0x0100000000ull; +#elif SANITIZER_TLS_WORKAROUND_NEEDED + const uptr kMadviseRangeBeg = kHiAppMemBeg; + const uptr kMadviseRangeSize = kHiAppMemEnd - kHiAppMemBeg; #endif NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg), kMadviseRangeSize * kShadowMultiplier); @@ -302,6 +305,18 @@ Die(); } +#if SANITIZER_TLS_WORKAROUND_NEEDED + // on aaarch64/android, the memory maps are significantly different + ProtectRange(kShadowEnd, kMetaShadowBeg); + ProtectRange(kMetaShadowEnd, kLoAppMemBeg); + ProtectRange(kLoAppMemEnd, kTraceMemBeg); + + // Memory for traces is mapped lazily in MapThreadTrace. + // Protect the whole range for now, so that user does not map something here. + ProtectRange(kTraceMemBeg, kTraceMemEnd); + ProtectRange(kTraceMemEnd, kHeapMemBeg); + //ProtectRange(HeapEnd(), kHiAppMemBeg); +#else ProtectRange(kLoAppMemEnd, kShadowBeg); ProtectRange(kShadowEnd, kMetaShadowBeg); ProtectRange(kMetaShadowEnd, kTraceMemBeg); @@ -310,6 +325,7 @@ ProtectRange(kTraceMemBeg, kTraceMemEnd); ProtectRange(kTraceMemEnd, kHeapMemBeg); ProtectRange(HeapEnd(), kHiAppMemBeg); +#endif } #endif // #ifndef SANITIZER_GO @@ -361,7 +377,7 @@ // This is required to properly "close" the fds, because we do not see internal // closes within glibc. The code is a pure hack. int ExtractResolvFDs(void *state, int *fds, int nfd) { -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID int cnt = 0; __res_state *statp = (__res_state*)state; for (int i = 0; i < MAXNS && cnt < nfd; i++) { Index: lib/tsan/rtl/tsan_rtl.h =================================================================== --- lib/tsan/rtl/tsan_rtl.h +++ lib/tsan/rtl/tsan_rtl.h @@ -34,6 +34,9 @@ #include "sanitizer_common/sanitizer_libignore.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_thread_registry.h" + +// this needs to be pulled in first +#include "tsan_aarch64_tls_workaround.h" #include "tsan_clock.h" #include "tsan_defs.h" #include "tsan_flags.h" @@ -54,7 +57,7 @@ #ifndef SANITIZER_GO struct MapUnmapCallback; -#ifdef __mips64 +#if defined(__mips64) || defined(__aarch64__) static const uptr kAllocatorSpace = 0; static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE; static const uptr kAllocatorRegionSizeLog = 20; @@ -410,11 +413,18 @@ }; #ifndef SANITIZER_GO +#if !SANITIZER_TLS_WORKAROUND_NEEDED __attribute__((tls_model("initial-exec"))) extern THREADLOCAL char cur_thread_placeholder[]; INLINE ThreadState *cur_thread() { - return reinterpret_cast(&cur_thread_placeholder); + return reinterpret_cast(&GetFromTLS(cur_thread_placeholder)); } +#else +extern char &get_from_tls_cur_thread_placeholder(); +INLINE ThreadState *cur_thread() { + return reinterpret_cast(&get_from_tls_cur_thread_placeholder()); +} +#endif #endif class ThreadContext : public ThreadContextBase { Index: lib/tsan/rtl/tsan_rtl.cc =================================================================== --- lib/tsan/rtl/tsan_rtl.cc +++ lib/tsan/rtl/tsan_rtl.cc @@ -44,7 +44,11 @@ namespace __tsan { #ifndef SANITIZER_GO +#if !SANITIZER_TLS_WORKAROUND_NEEDED THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64); +// these are the real accessor functions +extern char &get_from_tls_cur_thread_placeholder(); +#endif #endif static char ctx_placeholder[sizeof(Context)] ALIGNED(64); Context *ctx; @@ -290,7 +294,8 @@ continue; const uptr s = MemToShadow(p); const uptr m = (uptr)MemToMeta(p); - VPrintf(3, " checking pointer %p: shadow=%p meta=%p\n", p, s, m); + const uptr s1 = ShadowToMem(s); + VPrintf(3, " checking pointer %p: shadow=%p meta=%p s2m=%p\n", p, s, m, s1); CHECK(IsAppMem(p)); CHECK(IsShadowMem(s)); CHECK_EQ(p & ~(kShadowCell - 1), ShadowToMem(s)); @@ -335,7 +340,7 @@ // On MIPS, TSan initialization is run before // __pthread_initialize_minimal_internal() is finished, so we can not spawn // new threads. -#ifndef __mips__ +#if !defined(__mips__)&&!SANITIZER_TLS_WORKAROUND_NEEDED StartBackgroundThread(); SetSandboxingCallback(StopBackgroundThread); #endif