Index: lib/tsan/rtl/tsan_interceptors.h =================================================================== --- lib/tsan/rtl/tsan_interceptors.h +++ lib/tsan/rtl/tsan_interceptors.h @@ -32,7 +32,7 @@ Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \ Die(); \ } \ - if (thr->ignore_interceptors || thr->in_ignored_lib) \ + if (!thr->is_inited || thr->ignore_interceptors || thr->in_ignored_lib) \ return REAL(func)(__VA_ARGS__); \ /**/ Index: lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors.cc +++ lib/tsan/rtl/tsan_interceptors.cc @@ -48,6 +48,13 @@ #define __libc_realloc REAL(realloc) #define __libc_calloc REAL(calloc) #define __libc_free REAL(free) +#elif SANITIZER_ANDROID +#define __errno_location __errno +#define __libc_malloc REAL(malloc) +#define __libc_realloc REAL(realloc) +#define __libc_calloc REAL(calloc) +#define __libc_free REAL(free) +#define mallopt(a, b) #endif #if SANITIZER_LINUX || SANITIZER_FREEBSD @@ -103,10 +110,12 @@ extern "C" void _exit(int status); extern "C" int *__errno_location(); extern "C" int fileno_unlocked(void *stream); +#if !SANITIZER_ANDROID extern "C" void *__libc_calloc(uptr size, uptr n); extern "C" void *__libc_realloc(void *ptr, uptr size); +#endif extern "C" int dirfd(void *dirp); -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID extern "C" int mallopt(int param, int value); #endif extern __sanitizer_FILE *stdout, *stderr; @@ -149,6 +158,17 @@ typedef void (*sighandler_t)(int sig); typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx); +#if SANITIZER_ANDROID +struct sigaction_t { + u32 sa_flags; + union { + sighandler_t sa_handler; + sigactionhandler_t sa_sigaction; + }; + __sanitizer_sigset_t sa_mask; + void (*sa_restorer)(); +}; +#else struct sigaction_t { #ifdef __mips__ u32 sa_flags; @@ -168,6 +188,7 @@ void (*sa_restorer)(); #endif }; +#endif // SANITIZER_ANDROID const sighandler_t SIG_DFL = (sighandler_t)0; const sighandler_t SIG_IGN = (sighandler_t)1; @@ -201,6 +222,9 @@ atomic_uintptr_t in_blocking_func; atomic_uintptr_t have_pending_signals; SignalDesc pending_signals[kSigCount]; + // emptyset and oldset are too big for stack. + __sanitizer_sigset_t emptyset; + __sanitizer_sigset_t oldset; }; // The object is 64-byte aligned, because we want hot data to be located in @@ -223,6 +247,15 @@ } // namespace __tsan +static int __sigfillset(__sanitizer_sigset_t* sigset) { +#if SANITIZER_ANDROID + internal_sigfillset(sigset); + return 0; +#else + return REAL(sigfillset)(sigset); +#endif +} + static ThreadSignalContext *SigCtx(ThreadState *thr) { ThreadSignalContext *ctx = (ThreadSignalContext*)thr->signal_ctx; if (ctx == 0 && !thr->is_dead) { @@ -242,8 +275,11 @@ : thr_(thr) , pc_(pc) , in_ignored_lib_(false) { + Initialize(thr); + if (!thr_->is_inited) { + return; + } if (!thr_->ignore_interceptors) { - Initialize(thr); FuncEntry(thr, pc); } DPrintf("#%d: intercept %s()\n", thr_->tid, fname); @@ -255,6 +291,9 @@ } ScopedInterceptor::~ScopedInterceptor() { + if (!thr_->is_inited) { + return; + } if (in_ignored_lib_) { thr_->in_ignored_lib = false; ThreadIgnoreEnd(thr_, pc_); @@ -350,6 +389,7 @@ static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), void *arg, void *dso); +#if !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, atexit, void (*f)()) { if (cur_thread()->in_symbolizer) return 0; @@ -358,6 +398,7 @@ SCOPED_INTERCEPTOR_RAW(atexit, f); return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0); } +#endif TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) { if (cur_thread()->in_symbolizer) @@ -1324,7 +1365,7 @@ return 0; } -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf); READ_STRING(thr, pc, path, 0); @@ -1336,7 +1377,7 @@ #endif TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_MAC +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID SCOPED_TSAN_INTERCEPTOR(stat, path, buf); READ_STRING(thr, pc, path, 0); return REAL(stat)(path, buf); @@ -1347,7 +1388,7 @@ #endif } -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf); READ_STRING(thr, pc, path, 0); @@ -1358,7 +1399,7 @@ #define TSAN_MAYBE_INTERCEPT___XSTAT64 #endif -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf); READ_STRING(thr, pc, path, 0); @@ -1369,7 +1410,7 @@ #define TSAN_MAYBE_INTERCEPT_STAT64 #endif -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf); READ_STRING(thr, pc, path, 0); @@ -1381,7 +1422,7 @@ #endif TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_MAC +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID SCOPED_TSAN_INTERCEPTOR(lstat, path, buf); READ_STRING(thr, pc, path, 0); return REAL(lstat)(path, buf); @@ -1392,7 +1433,7 @@ #endif } -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf); READ_STRING(thr, pc, path, 0); @@ -1403,7 +1444,7 @@ #define TSAN_MAYBE_INTERCEPT___LXSTAT64 #endif -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf); READ_STRING(thr, pc, path, 0); @@ -1414,7 +1455,7 @@ #define TSAN_MAYBE_INTERCEPT_LSTAT64 #endif -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) { SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf); if (fd > 0) @@ -1427,7 +1468,7 @@ #endif TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_MAC +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf); if (fd > 0) FdAccess(thr, pc, fd); @@ -1440,7 +1481,7 @@ #endif } -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) { SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf); if (fd > 0) @@ -1452,7 +1493,7 @@ #define TSAN_MAYBE_INTERCEPT___FXSTAT64 #endif -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) { SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf); if (fd > 0) @@ -1677,7 +1718,7 @@ #endif // glibc guts -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) { SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr); int fds[64]; @@ -1909,10 +1950,8 @@ return; atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed); atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); - // 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)); + CHECK_EQ(0, __sigfillset(&sctx->emptyset)); + CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sctx->emptyset, &sctx->oldset)); for (int sig = 0; sig < kSigCount; sig++) { SignalDesc *signal = &sctx->pending_signals[sig]; if (signal->armed) { @@ -1921,7 +1960,7 @@ &signal->siginfo, &signal->ctx); } } - CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &oldset, 0)); + CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sctx->oldset, 0)); atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); } @@ -2015,7 +2054,7 @@ #endif sigaction_t newact; internal_memcpy(&newact, act, sizeof(newact)); - REAL(sigfillset)(&newact.sa_mask); + __sigfillset(&newact.sa_mask); if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL) { if (newact.sa_flags & SA_SIGINFO) newact.sa_sigaction = rtl_sigaction; @@ -2143,7 +2182,7 @@ return WRAP(fork)(fake); } -#if !SANITIZER_MAC +#if !SANITIZER_MAC && !SANITIZER_ANDROID typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size, void *data); struct dl_iterate_phdr_data { @@ -2465,7 +2504,7 @@ Die(); } -#if !SANITIZER_MAC +#if !SANITIZER_MAC && !SANITIZER_ANDROID static void unreachable() { Report("FATAL: ThreadSanitizer: unreachable called\n"); Die(); @@ -2630,12 +2669,14 @@ TSAN_INTERCEPT(fork); TSAN_INTERCEPT(vfork); +#if !SANITIZER_ANDROID TSAN_INTERCEPT(dl_iterate_phdr); +#endif TSAN_INTERCEPT(on_exit); TSAN_INTERCEPT(__cxa_atexit); TSAN_INTERCEPT(_exit); -#if !SANITIZER_MAC +#if !SANITIZER_MAC && !SANITIZER_ANDROID // Need to setup it, because interceptors check that the function is resolved. // But atexit is emitted directly into the module, so can't be resolved. REAL(atexit) = (int(*)(void(*)()))unreachable; Index: lib/tsan/rtl/tsan_new_delete.cc =================================================================== --- lib/tsan/rtl/tsan_new_delete.cc +++ lib/tsan/rtl/tsan_new_delete.cc @@ -23,7 +23,7 @@ DECLARE_REAL(void *, malloc, uptr size) DECLARE_REAL(void, free, void *ptr) -#if SANITIZER_MAC +#if SANITIZER_MAC || SANITIZER_ANDROID #define __libc_malloc REAL(malloc) #define __libc_free REAL(free) #endif Index: lib/tsan/rtl/tsan_platform.h =================================================================== --- lib/tsan/rtl/tsan_platform.h +++ lib/tsan/rtl/tsan_platform.h @@ -87,7 +87,39 @@ const uptr kAppMemXor = 0x0400000000ull; const uptr kVdsoBeg = 0xfffff00000ull; #elif defined(__aarch64__) -# if SANITIZER_AARCH64_VMA == 39 +# if SANITIZER_ANDROID +/* +C/C++ on android/aarch64 (39-bit VMA) +On Android, the executable file is shared library, so it is loaded +to address space near TASK_SIZE*2/3. Vdso area is not guaranteed +to be higher than stack, so disable it. +2000 0000 00 - 4000 0000 00: shadow memory +4000 0000 00 - 5000 0000 00: metainfo +5000 0000 00 - 5500 0000 00: - +5500 0000 00 - 5700 0000 00: main binary and heap +5700 0000 00 - 6000 0000 00: - +6000 0000 00 - 6200 0000 00: traces +6200 0000 00 - 7d00 0000 00: - +7d00 0000 00 - 7fff ffff ff: modules and main thread stack +*/ +const uptr kShadowBeg = 0x2000000000ull; +const uptr kShadowEnd = 0x4000000000ull; +const uptr kMetaShadowBeg = 0x4000000000ull; +const uptr kMetaShadowEnd = 0x5000000000ull; +const uptr kLoAppMemBeg = 0x5500000000ull; +const uptr kLoAppMemEnd = 0x5700000000ull; +const uptr kHeapMemBeg = 0x5700000000ull; +const uptr kHeapMemEnd = 0x5700000000ull; +const uptr kTraceMemBeg = 0x6000000000ull; +const uptr kTraceMemEnd = 0x6200000000ull; +const uptr kHiAppMemBeg = 0x7d00000000ull; +const uptr kHiAppMemEnd = 0x7fffffffffull; +const uptr kVdsoBeg = 0x7fffffffffull; +const uptr kLoAppMemAdd = 0x0300000000ull; +const uptr kLoAppMemMsk = 0x5000000000ull; +const uptr kHiAppMemMsk = 0x7000000000ull; + +# elif SANITIZER_AARCH64_VMA == 39 /* C/C++ on linux/aarch64 (39-bit VMA) 0000 4000 00 - 0200 0000 00: main binary @@ -167,24 +199,50 @@ ALWAYS_INLINE uptr MemToShadow(uptr x) { DCHECK(IsAppMem(x)); +#if SANITIZER_ANDROID && defined(__aarch64__) + if (x <= kLoAppMemEnd) { + return ((x & ~(kLoAppMemMsk | (kShadowCell - 1))) + kLoAppMemAdd) * kShadowCnt; + } else { + return ((x & ~(kHiAppMemMsk | (kShadowCell - 1)))) * kShadowCnt; + } +#else return (((x) & ~(kAppMemMsk | (kShadowCell - 1))) ^ kAppMemXor) * kShadowCnt; +#endif } ALWAYS_INLINE u32 *MemToMeta(uptr x) { DCHECK(IsAppMem(x)); +#if SANITIZER_ANDROID && defined(__aarch64__) + if (x <= kLoAppMemEnd) { + return (u32*)((((x & ~(kLoAppMemMsk | (kMetaShadowCell - 1))) + + kLoAppMemAdd) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg); + } else { + return (u32*)(((x & ~(kHiAppMemMsk | (kMetaShadowCell - 1))) + / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg); + } +#else return (u32*)(((((x) & ~(kAppMemMsk | (kMetaShadowCell - 1))) ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg); +#endif } ALWAYS_INLINE uptr ShadowToMem(uptr s) { CHECK(IsShadowMem(s)); +#if SANITIZER_ANDROID && defined(__aarch64__) + if (s <= MemToShadow(kLoAppMemEnd)) { + return ((s / kShadowCnt) - kLoAppMemAdd) | kLoAppMemMsk; + } else { + return ((s / kShadowCnt)) | kHiAppMemMsk; + } +#else if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1)) return (s / kShadowCnt) ^ kAppMemXor; else return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk; +#endif } static USED uptr UserRegions[] = { Index: lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- lib/tsan/rtl/tsan_platform_linux.cc +++ lib/tsan/rtl/tsan_platform_linux.cc @@ -18,6 +18,8 @@ #include "sanitizer_common/sanitizer_common.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_posix.h" #include "sanitizer_common/sanitizer_procmaps.h" #include "sanitizer_common/sanitizer_stoptheworld.h" @@ -283,7 +285,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++) { @@ -335,6 +337,67 @@ void ReplaceSystemMalloc() { } #endif + +#ifndef SANITIZER_GO +#if SANITIZER_ANDROID + +#if defined(__aarch64__) +# define __get_tls() ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; }) +#elif defined(__x86_64__) +# define __get_tls() ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; }) +#else +#error unsupported architecture +#endif + +// On android, __thread is not supported. So we store the pointer to ThreadState +// in one TLS slot. +#define TLS_SLOT_TSAN 8 +static ThreadState *dead_thread_state = nullptr; + +ThreadState *cur_thread() { + ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN]; + if (thr == nullptr) { + __sanitizer_sigset_t emptyset; + internal_sigfillset(&emptyset); + __sanitizer_sigset_t oldset; + CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset)); + thr = reinterpret_cast(__get_tls()[TLS_SLOT_TSAN]); + if (thr == nullptr) { + thr = reinterpret_cast(internal_mmap(nullptr, sizeof(ThreadState), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0)); + CHECK(thr); + __get_tls()[TLS_SLOT_TSAN] = thr; + if (dead_thread_state == nullptr) { + dead_thread_state = reinterpret_cast(internal_mmap(nullptr, + sizeof(ThreadState), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)); + CHECK(dead_thread_state); + dead_thread_state->fast_state.SetIgnoreBit(); + dead_thread_state->ignore_interceptors = 1; + dead_thread_state->is_dead = true; + *const_cast(&dead_thread_state->tid) = -1; + } + } + CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr)); + } + return thr; +} + +void cur_thread_finalize() { + __sanitizer_sigset_t emptyset; + internal_sigfillset(&emptyset); + __sanitizer_sigset_t oldset; + CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset)); + ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN]; + if (thr != dead_thread_state) { + __get_tls()[TLS_SLOT_TSAN] = dead_thread_state; + internal_munmap(thr, sizeof(ThreadState)); + } + CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr)); +} +#endif // SANITIZER_ANDROID +#endif // ifndef SANITIZER_GO + } // namespace __tsan #endif // SANITIZER_LINUX || SANITIZER_FREEBSD Index: lib/tsan/rtl/tsan_platform_posix.cc =================================================================== --- lib/tsan/rtl/tsan_platform_posix.cc +++ lib/tsan/rtl/tsan_platform_posix.cc @@ -108,14 +108,17 @@ Die(); } +#if !SANITIZER_ANDROID ProtectRange(kLoAppMemEnd, kShadowBeg); ProtectRange(kShadowEnd, kMetaShadowBeg); ProtectRange(kMetaShadowEnd, kTraceMemBeg); + ProtectRange(kTraceMemEnd, kHeapMemBeg); + ProtectRange(HeapEnd(), kHiAppMemBeg); +#endif // 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); + } #endif Index: lib/tsan/rtl/tsan_rtl.h =================================================================== --- lib/tsan/rtl/tsan_rtl.h +++ lib/tsan/rtl/tsan_rtl.h @@ -410,7 +410,7 @@ }; #ifndef SANITIZER_GO -#if SANITIZER_MAC +#if SANITIZER_MAC || SANITIZER_ANDROID ThreadState *cur_thread(); void cur_thread_finalize(); #else @@ -420,7 +420,7 @@ return reinterpret_cast(&cur_thread_placeholder); } INLINE void cur_thread_finalize() { } -#endif // SANITIZER_MAC +#endif // SANITIZER_MAC || SANITIZER_ANDROID #endif // SANITIZER_GO class ThreadContext : public ThreadContextBase { Index: lib/tsan/rtl/tsan_rtl.cc =================================================================== --- lib/tsan/rtl/tsan_rtl.cc +++ lib/tsan/rtl/tsan_rtl.cc @@ -289,7 +289,7 @@ const uptr beg = UserRegions[i]; const uptr end = UserRegions[i + 1]; VPrintf(3, "checking shadow region %p-%p\n", beg, end); - for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) { + for (uptr p0 = beg; p0 < end; p0 += (end - beg) / 4) { for (int x = -1; x <= 1; x++) { const uptr p = p0 + x; if (p < beg || p >= end) Index: test/tsan/test.h =================================================================== --- test/tsan/test.h +++ test/tsan/test.h @@ -53,7 +53,7 @@ else if (vma == 42) format = "0x%011lx"; else { - fprintf(stderr, "unsupported vma: %ul\n", vma); + fprintf(stderr, "unsupported vma: %lu\n", vma); exit(1); }