diff options
author | Jakub Jelinek <jakub@redhat.com> | 2023-11-15 12:45:58 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2023-11-15 12:45:58 +0100 |
commit | 28219f7f99a80519d1c6ab5e5dc83b4c7f8d7251 (patch) | |
tree | 42e3657c58ff08a654f04aeb0f43b3bc75930bbc /libsanitizer/tsan | |
parent | 4d86dc51e34d2a5695b617afeb56e3414836a79a (diff) | |
download | gcc-28219f7f99a80519d1c6ab5e5dc83b4c7f8d7251.zip gcc-28219f7f99a80519d1c6ab5e5dc83b4c7f8d7251.tar.gz gcc-28219f7f99a80519d1c6ab5e5dc83b4c7f8d7251.tar.bz2 |
libsanitizer: merge from upstream (c425db2eb558c263)
The following patch is result of libsanitizer/merge.sh
from c425db2eb558c263 (yesterday evening).
Bootstrapped/regtested on x86_64-linux and i686-linux (together with
the follow-up 3 patches I'm about to post).
BTW, seems upstream has added riscv64 support for I think lsan/tsan,
so if anyone is willing to try it there, it would be a matter of
copying e.g. the s390*-*-linux* libsanitizer/configure.tgt entry
to riscv64-*-linux* with the obvious s/s390x/riscv64/ change in it.
Diffstat (limited to 'libsanitizer/tsan')
21 files changed, 568 insertions, 179 deletions
diff --git a/libsanitizer/tsan/Makefile.am b/libsanitizer/tsan/Makefile.am index 01290b0..cb8bf2e 100644 --- a/libsanitizer/tsan/Makefile.am +++ b/libsanitizer/tsan/Makefile.am @@ -22,6 +22,7 @@ tsan_files = \ tsan_ignoreset.cpp \ tsan_interceptors_posix.cpp \ tsan_interceptors_mac.cpp \ + tsan_interceptors_memintrinsics.cpp \ tsan_interface_ann.cpp \ tsan_interface_atomic.cpp \ tsan_interface.cpp \ @@ -49,7 +50,7 @@ tsan_files = \ tsan_vector_clock.cpp libtsan_la_SOURCES = $(tsan_files) -EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S tsan_rtl_s390x.S +EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S tsan_rtl_s390x.S tsan_rtl_riscv64.S libtsan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(TSAN_TARGET_DEPENDENT_OBJECTS) libtsan_la_DEPENDENCIES = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(TSAN_TARGET_DEPENDENT_OBJECTS) if LIBBACKTRACE_SUPPORTED diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in index 9501158..fc14a42 100644 --- a/libsanitizer/tsan/Makefile.in +++ b/libsanitizer/tsan/Makefile.in @@ -148,10 +148,10 @@ LTLIBRARIES = $(toolexeclib_LTLIBRARIES) am__DEPENDENCIES_1 = am__objects_1 = tsan_debugging.lo tsan_external.lo tsan_fd.lo \ tsan_flags.lo tsan_ignoreset.lo tsan_interceptors_posix.lo \ - tsan_interceptors_mac.lo tsan_interface_ann.lo \ - tsan_interface_atomic.lo tsan_interface.lo \ - tsan_interface_java.lo tsan_malloc_mac.lo tsan_md5.lo \ - tsan_mman.lo tsan_mutexset.lo tsan_new_delete.lo \ + tsan_interceptors_mac.lo tsan_interceptors_memintrinsics.lo \ + tsan_interface_ann.lo tsan_interface_atomic.lo \ + tsan_interface.lo tsan_interface_java.lo tsan_malloc_mac.lo \ + tsan_md5.lo tsan_mman.lo tsan_mutexset.lo tsan_new_delete.lo \ tsan_platform_linux.lo tsan_platform_mac.lo \ tsan_platform_posix.lo tsan_platform_windows.lo tsan_report.lo \ tsan_rtl.lo tsan_rtl_access.lo tsan_rtl_mutex.lo \ @@ -427,6 +427,7 @@ tsan_files = \ tsan_ignoreset.cpp \ tsan_interceptors_posix.cpp \ tsan_interceptors_mac.cpp \ + tsan_interceptors_memintrinsics.cpp \ tsan_interface_ann.cpp \ tsan_interface_atomic.cpp \ tsan_interface.cpp \ @@ -454,7 +455,7 @@ tsan_files = \ tsan_vector_clock.cpp libtsan_la_SOURCES = $(tsan_files) -EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S tsan_rtl_s390x.S +EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S tsan_rtl_s390x.S tsan_rtl_riscv64.S libtsan_la_LIBADD = \ $(top_builddir)/sanitizer_common/libsanitizer_common.la \ $(top_builddir)/interception/libinterception.la \ @@ -592,6 +593,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_flags.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_ignoreset.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interceptors_mac.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interceptors_memintrinsics.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interceptors_posix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface_ann.Plo@am__quote@ @@ -616,6 +618,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_ppc64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_proc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_report.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_riscv64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_s390x.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_stack_trace.Plo@am__quote@ diff --git a/libsanitizer/tsan/tsan_debugging.cpp b/libsanitizer/tsan/tsan_debugging.cpp index 1e61c31..41fa293 100644 --- a/libsanitizer/tsan/tsan_debugging.cpp +++ b/libsanitizer/tsan/tsan_debugging.cpp @@ -35,7 +35,9 @@ static const char *ReportTypeDescription(ReportType typ) { case ReportTypeSignalUnsafe: return "signal-unsafe-call"; case ReportTypeErrnoInSignal: return "errno-in-signal-handler"; case ReportTypeDeadlock: return "lock-order-inversion"; - // No default case so compiler warns us if we miss one + case ReportTypeMutexHeldWrongContext: + return "mutex-held-in-wrong-context"; + // No default case so compiler warns us if we miss one } UNREACHABLE("missing case"); } diff --git a/libsanitizer/tsan/tsan_interceptors.h b/libsanitizer/tsan/tsan_interceptors.h index 60fbc58..a357a87 100644 --- a/libsanitizer/tsan/tsan_interceptors.h +++ b/libsanitizer/tsan/tsan_interceptors.h @@ -29,6 +29,11 @@ class ScopedInterceptor { void EnableIgnoresImpl(); }; +struct TsanInterceptorContext { + ThreadState *thr; + const uptr pc; +}; + LibIgnore *libignore(); #if !SANITIZER_GO @@ -82,7 +87,7 @@ inline bool MustIgnoreInterceptor(ThreadState *thr) { #if SANITIZER_FREEBSD # define TSAN_INTERCEPTOR_FREEBSD_ALIAS(ret, func, ...) \ TSAN_INTERCEPTOR(ret, _pthread_##func, __VA_ARGS__) \ - ALIAS(WRAPPER_NAME(pthread_##func)); + ALIAS(WRAP(pthread_##func)); #else # define TSAN_INTERCEPTOR_FREEBSD_ALIAS(ret, func, ...) #endif @@ -90,17 +95,38 @@ inline bool MustIgnoreInterceptor(ThreadState *thr) { #if SANITIZER_NETBSD # define TSAN_INTERCEPTOR_NETBSD_ALIAS(ret, func, ...) \ TSAN_INTERCEPTOR(ret, __libc_##func, __VA_ARGS__) \ - ALIAS(WRAPPER_NAME(pthread_##func)); + ALIAS(WRAP(pthread_##func)); # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(ret, func, ...) \ TSAN_INTERCEPTOR(ret, __libc_thr_##func, __VA_ARGS__) \ - ALIAS(WRAPPER_NAME(pthread_##func)); + ALIAS(WRAP(pthread_##func)); # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(ret, func, func2, ...) \ TSAN_INTERCEPTOR(ret, __libc_thr_##func, __VA_ARGS__) \ - ALIAS(WRAPPER_NAME(pthread_##func2)); + ALIAS(WRAP(pthread_##func2)); #else # define TSAN_INTERCEPTOR_NETBSD_ALIAS(ret, func, ...) # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(ret, func, ...) # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(ret, func, func2, ...) #endif +#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) + +#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \ + (!cur_thread_init()->is_inited) + +#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ + MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \ + ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \ + true) + +#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ + MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr, \ + ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \ + false) + +#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ + SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__); \ + TsanInterceptorContext _ctx = {thr, pc}; \ + ctx = (void *)&_ctx; \ + (void)ctx; + #endif // TSAN_INTERCEPTORS_H diff --git a/libsanitizer/tsan/tsan_interceptors_libdispatch.cpp b/libsanitizer/tsan/tsan_interceptors_libdispatch.cpp index 88d5f0a..2104fe7 100644 --- a/libsanitizer/tsan/tsan_interceptors_libdispatch.cpp +++ b/libsanitizer/tsan/tsan_interceptors_libdispatch.cpp @@ -558,7 +558,7 @@ TSAN_INTERCEPTOR(void, dispatch_apply_f, size_t iterations, } DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) -DECLARE_REAL_AND_INTERCEPTOR(int, munmap, void *addr, long_t sz) +DECLARE_REAL_AND_INTERCEPTOR(int, munmap, void *addr, SIZE_T sz) TSAN_INTERCEPTOR(dispatch_data_t, dispatch_data_create, const void *buffer, size_t size, dispatch_queue_t q, dispatch_block_t destructor) { diff --git a/libsanitizer/tsan/tsan_interceptors_memintrinsics.cpp b/libsanitizer/tsan/tsan_interceptors_memintrinsics.cpp new file mode 100644 index 0000000..c8b6b2e --- /dev/null +++ b/libsanitizer/tsan/tsan_interceptors_memintrinsics.cpp @@ -0,0 +1,43 @@ +//===-- tsan_interceptors_posix.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer (TSan), a race detector. +// +//===----------------------------------------------------------------------===// + +#define SANITIZER_COMMON_NO_REDEFINE_BUILTINS + +#include "tsan_interceptors.h" +#include "tsan_interface.h" + +using namespace __tsan; + +#include "sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc" + +extern "C" { + +void *__tsan_memcpy(void *dst, const void *src, uptr size) { + void *ctx; +#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE + COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size); +#else + COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); +#endif +} + +void *__tsan_memset(void *dst, int c, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, c, size); +} + +void *__tsan_memmove(void *dst, const void *src, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); +} + +} // extern "C" diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp index 6ac6ac6..80f86ca 100644 --- a/libsanitizer/tsan/tsan_interceptors_posix.cpp +++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp @@ -35,6 +35,9 @@ using namespace __tsan; +DECLARE_REAL(void *, memcpy, void *to, const void *from, SIZE_T size) +DECLARE_REAL(void *, memset, void *block, int c, SIZE_T size) + #if SANITIZER_FREEBSD || SANITIZER_APPLE #define stdout __stdoutp #define stderr __stderrp @@ -78,6 +81,8 @@ struct ucontext_t { #define PTHREAD_ABI_BASE "GLIBC_2.17" #elif SANITIZER_LOONGARCH64 #define PTHREAD_ABI_BASE "GLIBC_2.36" +#elif SANITIZER_RISCV64 +# define PTHREAD_ABI_BASE "GLIBC_2.27" #endif extern "C" int pthread_attr_init(void *attr); @@ -128,7 +133,9 @@ const int SIGSYS = 12; const int SIGBUS = 7; const int SIGSYS = 31; #endif +#if SANITIZER_HAS_SIGINFO const int SI_TIMER = -2; +#endif void *const MAP_FAILED = (void*)-1; #if SANITIZER_NETBSD const int PTHREAD_BARRIER_SERIAL_THREAD = 1234567; @@ -156,9 +163,6 @@ const int SA_SIGINFO = 4; const int SIG_SETMASK = 2; #endif -#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \ - (!cur_thread_init()->is_inited) - namespace __tsan { struct SignalDesc { bool armed; @@ -592,58 +596,27 @@ TSAN_INTERCEPTOR(int, sigsetjmp, void *env); #define sigsetjmp_symname sigsetjmp #endif -#define TSAN_INTERCEPTOR_SETJMP_(x) __interceptor_ ## x -#define TSAN_INTERCEPTOR_SETJMP__(x) TSAN_INTERCEPTOR_SETJMP_(x) -#define TSAN_INTERCEPTOR_SETJMP TSAN_INTERCEPTOR_SETJMP__(setjmp_symname) -#define TSAN_INTERCEPTOR_SIGSETJMP TSAN_INTERCEPTOR_SETJMP__(sigsetjmp_symname) - -#define TSAN_STRING_SETJMP SANITIZER_STRINGIFY(setjmp_symname) -#define TSAN_STRING_SIGSETJMP SANITIZER_STRINGIFY(sigsetjmp_symname) - -// Not called. Merely to satisfy TSAN_INTERCEPT(). -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int TSAN_INTERCEPTOR_SETJMP(void *env); -extern "C" int TSAN_INTERCEPTOR_SETJMP(void *env) { - CHECK(0); - return 0; -} - -// FIXME: any reason to have a separate declaration? -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int __interceptor__setjmp(void *env); -extern "C" int __interceptor__setjmp(void *env) { - CHECK(0); - return 0; -} - -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int TSAN_INTERCEPTOR_SIGSETJMP(void *env); -extern "C" int TSAN_INTERCEPTOR_SIGSETJMP(void *env) { - CHECK(0); - return 0; -} - -#if !SANITIZER_NETBSD -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int __interceptor___sigsetjmp(void *env); -extern "C" int __interceptor___sigsetjmp(void *env) { - CHECK(0); - return 0; -} -#endif - -extern "C" int setjmp_symname(void *env); -extern "C" int _setjmp(void *env); -extern "C" int sigsetjmp_symname(void *env); -#if !SANITIZER_NETBSD -extern "C" int __sigsetjmp(void *env); -#endif DEFINE_REAL(int, setjmp_symname, void *env) DEFINE_REAL(int, _setjmp, void *env) DEFINE_REAL(int, sigsetjmp_symname, void *env) #if !SANITIZER_NETBSD DEFINE_REAL(int, __sigsetjmp, void *env) #endif + +// The real interceptor for setjmp is special, and implemented in pure asm. We +// just need to initialize the REAL functions so that they can be used in asm. +static void InitializeSetjmpInterceptors() { + // We can not use TSAN_INTERCEPT to get setjmp addr, because it does &setjmp and + // setjmp is not present in some versions of libc. + using __interception::InterceptFunction; + InterceptFunction(SANITIZER_STRINGIFY(setjmp_symname), (uptr*)&REAL(setjmp_symname), 0, 0); + InterceptFunction("_setjmp", (uptr*)&REAL(_setjmp), 0, 0); + InterceptFunction(SANITIZER_STRINGIFY(sigsetjmp_symname), (uptr*)&REAL(sigsetjmp_symname), 0, + 0); +#if !SANITIZER_NETBSD + InterceptFunction("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0); +#endif +} #endif // SANITIZER_APPLE #if SANITIZER_NETBSD @@ -824,10 +797,11 @@ static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap, return res; } -TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { - SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz); +template <class Munmap> +static int munmap_interceptor(ThreadState *thr, uptr pc, Munmap real_munmap, + void *addr, SIZE_T sz) { UnmapShadow(thr, (uptr)addr, sz); - int res = REAL(munmap)(addr, sz); + int res = real_munmap(addr, sz); return res; } @@ -2420,11 +2394,6 @@ static int OnExit(ThreadState *thr) { return status; } -struct TsanInterceptorContext { - ThreadState *thr; - const uptr pc; -}; - #if !SANITIZER_APPLE static void HandleRecvmsg(ThreadState *thr, uptr pc, __sanitizer_msghdr *msg) { @@ -2446,28 +2415,11 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc, #define SANITIZER_INTERCEPT_TLS_GET_OFFSET 1 #undef SANITIZER_INTERCEPT_PTHREAD_SIGMASK -#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ INTERCEPT_FUNCTION_VER(name, ver) #define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \ (INTERCEPT_FUNCTION_VER(name, ver) || INTERCEPT_FUNCTION(name)) -#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ - MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \ - ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \ - true) - -#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ - MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr, \ - ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \ - false) - -#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ - SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__); \ - TsanInterceptorContext _ctx = {thr, pc}; \ - ctx = (void *)&_ctx; \ - (void)ctx; - #define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \ TsanInterceptorContext _ctx = {thr, pc}; \ @@ -2555,6 +2507,11 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc, off); \ } while (false) +#define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, sz) \ + do { \ + return munmap_interceptor(thr, pc, REAL(munmap), addr, sz); \ + } while (false) + #if !SANITIZER_APPLE #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ @@ -2588,6 +2545,8 @@ static __sanitizer_sighandler_ptr signal_impl(int sig, #define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \ { return (uptr)signal_impl(signo, (__sanitizer_sighandler_ptr)handler); } +#define SIGNAL_INTERCEPTOR_ENTER() LazyInitialize(cur_thread_init()) + #include "sanitizer_common/sanitizer_signal_interceptors.inc" int sigaction_impl(int sig, const __sanitizer_sigaction *act, @@ -2608,7 +2567,7 @@ int sigaction_impl(int sig, const __sanitizer_sigaction *act, // Copy act into sigactions[sig]. // Can't use struct copy, because compiler can emit call to memcpy. // Can't use internal_memcpy, because it copies byte-by-byte, - // and signal handler reads the handler concurrently. It it can read + // and signal handler reads the handler concurrently. It can read // some bytes from old value and some bytes from new value. // Use volatile to prevent insertion of memcpy. sigactions[sig].handler = @@ -2893,16 +2852,7 @@ void InitializeInterceptors() { InitializeLibdispatchInterceptors(); #if !SANITIZER_APPLE - // We can not use TSAN_INTERCEPT to get setjmp addr, - // because it does &setjmp and setjmp is not present in some versions of libc. - using __interception::InterceptFunction; - InterceptFunction(TSAN_STRING_SETJMP, (uptr*)&REAL(setjmp_symname), 0, 0); - InterceptFunction("_setjmp", (uptr*)&REAL(_setjmp), 0, 0); - InterceptFunction(TSAN_STRING_SIGSETJMP, (uptr*)&REAL(sigsetjmp_symname), 0, - 0); -#if !SANITIZER_NETBSD - InterceptFunction("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0); -#endif + InitializeSetjmpInterceptors(); #endif TSAN_INTERCEPT(longjmp_symname); @@ -3169,22 +3119,4 @@ SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_wait( } } -void *__tsan_memcpy(void *dst, const void *src, uptr size) { - void *ctx; -#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE - COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size); -#else - COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); -#endif -} - -void *__tsan_memset(void *dst, int c, uptr size) { - void *ctx; - COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, c, size); -} - -void *__tsan_memmove(void *dst, const void *src, uptr size) { - void *ctx; - COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); -} -} +} // extern "C" diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h index d53c1e3..3731c90 100644 --- a/libsanitizer/tsan/tsan_interface.h +++ b/libsanitizer/tsan/tsan_interface.h @@ -419,6 +419,14 @@ void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a); SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a); SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_go_atomic32_fetch_and(ThreadState *thr, uptr cpc, uptr pc, u8 *a); +SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_go_atomic64_fetch_and(ThreadState *thr, uptr cpc, uptr pc, u8 *a); +SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_go_atomic32_fetch_or(ThreadState *thr, uptr cpc, uptr pc, u8 *a); +SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_go_atomic64_fetch_or(ThreadState *thr, uptr cpc, uptr pc, u8 *a); +SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a); SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a); diff --git a/libsanitizer/tsan/tsan_interface_ann.cpp b/libsanitizer/tsan/tsan_interface_ann.cpp index 6bd72e1..5154662 100644 --- a/libsanitizer/tsan/tsan_interface_ann.cpp +++ b/libsanitizer/tsan/tsan_interface_ann.cpp @@ -435,4 +435,26 @@ void __tsan_mutex_post_divert(void *addr, unsigned flagz) { ThreadIgnoreBegin(thr, 0); ThreadIgnoreSyncBegin(thr, 0); } + +static void ReportMutexHeldWrongContext(ThreadState *thr, uptr pc) { + ThreadRegistryLock l(&ctx->thread_registry); + ScopedReport rep(ReportTypeMutexHeldWrongContext); + for (uptr i = 0; i < thr->mset.Size(); ++i) { + MutexSet::Desc desc = thr->mset.Get(i); + rep.AddMutex(desc.addr, desc.stack_id); + } + VarSizeStackTrace trace; + ObtainCurrentStack(thr, pc, &trace); + rep.AddStack(trace, true); + OutputReport(thr, rep); +} + +INTERFACE_ATTRIBUTE +void __tsan_check_no_mutexes_held() { + SCOPED_ANNOTATION(__tsan_check_no_mutexes_held); + if (thr->mset.Size() == 0) { + return; + } + ReportMutexHeldWrongContext(thr, pc); +} } // extern "C" diff --git a/libsanitizer/tsan/tsan_interface_atomic.cpp b/libsanitizer/tsan/tsan_interface_atomic.cpp index f794a2f..2b5a2c6 100644 --- a/libsanitizer/tsan/tsan_interface_atomic.cpp +++ b/libsanitizer/tsan/tsan_interface_atomic.cpp @@ -895,6 +895,30 @@ void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { } SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_go_atomic32_fetch_and(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { + ATOMIC_RET(FetchAnd, *(a32 *)(a + 16), *(a32 **)a, *(a32 *)(a + 8), + mo_acq_rel); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_go_atomic64_fetch_and(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { + ATOMIC_RET(FetchAnd, *(a64 *)(a + 16), *(a64 **)a, *(a64 *)(a + 8), + mo_acq_rel); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_go_atomic32_fetch_or(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { + ATOMIC_RET(FetchOr, *(a32 *)(a + 16), *(a32 **)a, *(a32 *)(a + 8), + mo_acq_rel); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __tsan_go_atomic64_fetch_or(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { + ATOMIC_RET(FetchOr, *(a64 *)(a + 16), *(a64 **)a, *(a64 *)(a + 8), + mo_acq_rel); +} + +SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { ATOMIC_RET(Exchange, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel); } diff --git a/libsanitizer/tsan/tsan_malloc_mac.cpp b/libsanitizer/tsan/tsan_malloc_mac.cpp index ac844ae..e973be9 100644 --- a/libsanitizer/tsan/tsan_malloc_mac.cpp +++ b/libsanitizer/tsan/tsan_malloc_mac.cpp @@ -17,6 +17,7 @@ #include "sanitizer_common/sanitizer_errno.h" #include "tsan_interceptors.h" #include "tsan_stack_trace.h" +#include "tsan_mman.h" using namespace __tsan; #define COMMON_MALLOC_ZONE_NAME "tsan" @@ -29,16 +30,30 @@ using namespace __tsan; user_memalign(cur_thread(), StackTrace::GetCurrentPc(), alignment, size) #define COMMON_MALLOC_MALLOC(size) \ if (in_symbolizer()) return InternalAlloc(size); \ - SCOPED_INTERCEPTOR_RAW(malloc, size); \ - void *p = user_alloc(thr, pc, size) + void *p = 0; \ + { \ + SCOPED_INTERCEPTOR_RAW(malloc, size); \ + p = user_alloc(thr, pc, size); \ + } \ + invoke_malloc_hook(p, size) #define COMMON_MALLOC_REALLOC(ptr, size) \ if (in_symbolizer()) return InternalRealloc(ptr, size); \ - SCOPED_INTERCEPTOR_RAW(realloc, ptr, size); \ - void *p = user_realloc(thr, pc, ptr, size) + if (ptr) \ + invoke_free_hook(ptr); \ + void *p = 0; \ + { \ + SCOPED_INTERCEPTOR_RAW(realloc, ptr, size); \ + p = user_realloc(thr, pc, ptr, size); \ + } \ + invoke_malloc_hook(p, size) #define COMMON_MALLOC_CALLOC(count, size) \ if (in_symbolizer()) return InternalCalloc(count, size); \ - SCOPED_INTERCEPTOR_RAW(calloc, size, count); \ - void *p = user_calloc(thr, pc, size, count) + void *p = 0; \ + { \ + SCOPED_INTERCEPTOR_RAW(calloc, size, count); \ + p = user_calloc(thr, pc, size, count); \ + } \ + invoke_malloc_hook(p, size * count) #define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \ if (in_symbolizer()) { \ void *p = InternalAlloc(size, nullptr, alignment); \ @@ -55,6 +70,7 @@ using namespace __tsan; void *p = user_valloc(thr, pc, size) #define COMMON_MALLOC_FREE(ptr) \ if (in_symbolizer()) return InternalFree(ptr); \ + invoke_free_hook(ptr); \ SCOPED_INTERCEPTOR_RAW(free, ptr); \ user_free(thr, pc, ptr) #define COMMON_MALLOC_SIZE(ptr) uptr size = user_alloc_usable_size(ptr); diff --git a/libsanitizer/tsan/tsan_mman.cpp b/libsanitizer/tsan/tsan_mman.cpp index e5271cf..6f118e0 100644 --- a/libsanitizer/tsan/tsan_mman.cpp +++ b/libsanitizer/tsan/tsan_mman.cpp @@ -25,6 +25,8 @@ namespace __tsan { struct MapUnmapCallback { void OnMap(uptr p, uptr size) const { } + void OnMapSecondary(uptr p, uptr size, uptr user_begin, + uptr user_size) const {}; void OnUnmap(uptr p, uptr size) const { // We are about to unmap a chunk of user memory. // Mark the corresponding shadow memory as not needed. @@ -377,6 +379,17 @@ uptr user_alloc_usable_size(const void *p) { return b->siz; } +uptr user_alloc_usable_size_fast(const void *p) { + MBlock *b = ctx->metamap.GetBlock((uptr)p); + // Static objects may have malloc'd before tsan completes + // initialization, and may believe returned ptrs to be valid. + if (!b) + return 0; // Not a valid pointer. + if (b->siz == 0) + return 1; // Zero-sized allocations are actually 1 byte. + return b->siz; +} + void invoke_malloc_hook(void *ptr, uptr size) { ThreadState *thr = cur_thread(); if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors) @@ -452,6 +465,17 @@ uptr __sanitizer_get_allocated_size(const void *p) { return user_alloc_usable_size(p); } +uptr __sanitizer_get_allocated_size_fast(const void *p) { + DCHECK_EQ(p, __sanitizer_get_allocated_begin(p)); + uptr ret = user_alloc_usable_size_fast(p); + DCHECK_EQ(ret, __sanitizer_get_allocated_size(p)); + return ret; +} + +void __sanitizer_purge_allocator() { + allocator()->ForceReleaseToOS(); +} + void __tsan_on_thread_idle() { ThreadState *thr = cur_thread(); allocator()->SwallowCache(&thr->proc()->alloc_cache); diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h index f0cdaf4..d9ed397 100644 --- a/libsanitizer/tsan/tsan_platform.h +++ b/libsanitizer/tsan/tsan_platform.h @@ -46,17 +46,16 @@ enum { /* C/C++ on linux/x86_64 and freebsd/x86_64 -0000 0000 1000 - 0080 0000 0000: main binary and/or MAP_32BIT mappings (512GB) -0040 0000 0000 - 0100 0000 0000: - -0100 0000 0000 - 1000 0000 0000: shadow -1000 0000 0000 - 3000 0000 0000: - -3000 0000 0000 - 3400 0000 0000: metainfo (memory blocks and sync objects) -3400 0000 0000 - 5500 0000 0000: - -5500 0000 0000 - 5680 0000 0000: pie binaries without ASLR or on 4.1+ kernels -5680 0000 0000 - 7d00 0000 0000: - -7b00 0000 0000 - 7c00 0000 0000: heap -7c00 0000 0000 - 7e80 0000 0000: - -7e80 0000 0000 - 8000 0000 0000: modules and main thread stack +0000 0000 1000 - 0200 0000 0000: main binary and/or MAP_32BIT mappings (2TB) +0200 0000 0000 - 1000 0000 0000: - +1000 0000 0000 - 3000 0000 0000: shadow (32TB) +3000 0000 0000 - 3800 0000 0000: metainfo (memory blocks and sync objects; 8TB) +3800 0000 0000 - 5500 0000 0000: - +5500 0000 0000 - 5a00 0000 0000: pie binaries without ASLR or on 4.1+ kernels +5a00 0000 0000 - 7200 0000 0000: - +7200 0000 0000 - 7300 0000 0000: heap (1TB) +7300 0000 0000 - 7a00 0000 0000: - +7a00 0000 0000 - 8000 0000 0000: modules and main thread stack (6TB) C/C++ on netbsd/amd64 can reuse the same mapping: * The address space starts from 0x1000 (option with 0x0) and ends with @@ -72,20 +71,20 @@ C/C++ on netbsd/amd64 can reuse the same mapping: */ struct Mapping48AddressSpace { static const uptr kMetaShadowBeg = 0x300000000000ull; - static const uptr kMetaShadowEnd = 0x340000000000ull; - static const uptr kShadowBeg = 0x010000000000ull; - static const uptr kShadowEnd = 0x100000000000ull; - static const uptr kHeapMemBeg = 0x7b0000000000ull; - static const uptr kHeapMemEnd = 0x7c0000000000ull; + static const uptr kMetaShadowEnd = 0x380000000000ull; + static const uptr kShadowBeg = 0x100000000000ull; + static const uptr kShadowEnd = 0x300000000000ull; + static const uptr kHeapMemBeg = 0x720000000000ull; + static const uptr kHeapMemEnd = 0x730000000000ull; static const uptr kLoAppMemBeg = 0x000000001000ull; - static const uptr kLoAppMemEnd = 0x008000000000ull; + static const uptr kLoAppMemEnd = 0x020000000000ull; static const uptr kMidAppMemBeg = 0x550000000000ull; - static const uptr kMidAppMemEnd = 0x568000000000ull; - static const uptr kHiAppMemBeg = 0x7e8000000000ull; + static const uptr kMidAppMemEnd = 0x5a0000000000ull; + static const uptr kHiAppMemBeg = 0x7a0000000000ull; static const uptr kHiAppMemEnd = 0x800000000000ull; - static const uptr kShadowMsk = 0x780000000000ull; - static const uptr kShadowXor = 0x040000000000ull; - static const uptr kShadowAdd = 0x000000000000ull; + static const uptr kShadowMsk = 0x700000000000ull; + static const uptr kShadowXor = 0x000000000000ull; + static const uptr kShadowAdd = 0x100000000000ull; static const uptr kVdsoBeg = 0xf000000000000000ull; }; @@ -378,6 +377,71 @@ struct MappingPPC64_47 { }; /* +C/C++ on linux/riscv64 (39-bit VMA) +0000 0010 00 - 0200 0000 00: main binary ( 8 GB) +0200 0000 00 - 1000 0000 00: - +1000 0000 00 - 4000 0000 00: shadow memory (64 GB) +4000 0000 00 - 4800 0000 00: metainfo (16 GB) +4800 0000 00 - 5500 0000 00: - +5500 0000 00 - 5a00 0000 00: main binary (PIE) (~8 GB) +5600 0000 00 - 7c00 0000 00: - +7d00 0000 00 - 7fff ffff ff: libraries and main thread stack ( 8 GB) + +mmap by default allocates from top downwards +VDSO sits below loader and above dynamic libraries, within HiApp region. +Heap starts after program region whose position depends on pie or non-pie. +Disable tracking them since their locations are not fixed. +*/ +struct MappingRiscv64_39 { + static const uptr kLoAppMemBeg = 0x0000001000ull; + static const uptr kLoAppMemEnd = 0x0200000000ull; + static const uptr kShadowBeg = 0x1000000000ull; + static const uptr kShadowEnd = 0x2000000000ull; + static const uptr kMetaShadowBeg = 0x2000000000ull; + static const uptr kMetaShadowEnd = 0x2400000000ull; + static const uptr kMidAppMemBeg = 0x2aaaaaa000ull; + static const uptr kMidAppMemEnd = 0x2c00000000ull; + static const uptr kHeapMemBeg = 0x2c00000000ull; + static const uptr kHeapMemEnd = 0x2c00000000ull; + static const uptr kHiAppMemBeg = 0x3c00000000ull; + static const uptr kHiAppMemEnd = 0x3fffffffffull; + static const uptr kShadowMsk = 0x3800000000ull; + static const uptr kShadowXor = 0x0800000000ull; + static const uptr kShadowAdd = 0x0000000000ull; + static const uptr kVdsoBeg = 0x4000000000ull; +}; + +/* +C/C++ on linux/riscv64 (48-bit VMA) +0000 0000 1000 - 0500 0000 0000: main binary ( 5 TB) +0500 0000 0000 - 2000 0000 0000: - +2000 0000 0000 - 4000 0000 0000: shadow memory (32 TB) +4000 0000 0000 - 4800 0000 0000: metainfo ( 8 TB) +4800 0000 0000 - 5555 5555 5000: - +5555 5555 5000 - 5a00 0000 0000: main binary (PIE) (~5 TB) +5a00 0000 0000 - 7a00 0000 0000: - +7a00 0000 0000 - 7fff ffff ffff: libraries and main thread stack ( 5 TB) +*/ +struct MappingRiscv64_48 { + static const uptr kLoAppMemBeg = 0x000000001000ull; + static const uptr kLoAppMemEnd = 0x050000000000ull; + static const uptr kShadowBeg = 0x200000000000ull; + static const uptr kShadowEnd = 0x400000000000ull; + static const uptr kMetaShadowBeg = 0x400000000000ull; + static const uptr kMetaShadowEnd = 0x480000000000ull; + static const uptr kMidAppMemBeg = 0x555555555000ull; + static const uptr kMidAppMemEnd = 0x5a0000000000ull; + static const uptr kHeapMemBeg = 0x5a0000000000ull; + static const uptr kHeapMemEnd = 0x5a0000000000ull; + static const uptr kHiAppMemBeg = 0x7a0000000000ull; + static const uptr kHiAppMemEnd = 0x7fffffffffffull; + static const uptr kShadowMsk = 0x700000000000ull; + static const uptr kShadowXor = 0x100000000000ull; + static const uptr kShadowAdd = 0x000000000000ull; + static const uptr kVdsoBeg = 0x800000000000ull; +}; + +/* C/C++ on linux/s390x While the kernel provides a 64-bit address space, we have to restrict ourselves to 48 bits due to how e.g. SyncVar::GetId() works. @@ -665,6 +729,13 @@ ALWAYS_INLINE auto SelectMapping(Arg arg) { } # elif defined(__mips64) return Func::template Apply<MappingMips64_40>(arg); +# elif SANITIZER_RISCV64 + switch (vmaSize) { + case 39: + return Func::template Apply<MappingRiscv64_39>(arg); + case 48: + return Func::template Apply<MappingRiscv64_48>(arg); + } # elif defined(__s390x__) return Func::template Apply<MappingS390x>(arg); # else @@ -686,6 +757,8 @@ void ForEachMapping() { Func::template Apply<MappingPPC64_44>(); Func::template Apply<MappingPPC64_46>(); Func::template Apply<MappingPPC64_47>(); + Func::template Apply<MappingRiscv64_39>(); + Func::template Apply<MappingRiscv64_48>(); Func::template Apply<MappingS390x>(); Func::template Apply<MappingGo48>(); Func::template Apply<MappingGoWindows>(); @@ -894,7 +967,7 @@ struct RestoreAddrImpl { Mapping::kMidAppMemEnd, Mapping::kHiAppMemBeg, Mapping::kHiAppMemEnd, Mapping::kHeapMemBeg, Mapping::kHeapMemEnd, }; - const uptr indicator = 0x0e0000000000ull; + const uptr indicator = 0x0f0000000000ull; const uptr ind_lsb = 1ull << LeastSignificantSetBitIndex(indicator); for (uptr i = 0; i < ARRAY_SIZE(ranges); i += 2) { uptr beg = ranges[i]; diff --git a/libsanitizer/tsan/tsan_platform_linux.cpp b/libsanitizer/tsan/tsan_platform_linux.cpp index 384a443..369509e 100644 --- a/libsanitizer/tsan/tsan_platform_linux.cpp +++ b/libsanitizer/tsan/tsan_platform_linux.cpp @@ -152,7 +152,7 @@ void WriteMemoryProfile(char *buf, uptr buf_size, u64 uptime_ns) { #if !SANITIZER_GO // Mark shadow for .rodata sections with the special Shadow::kRodata marker. // Accesses to .rodata can't race, so this saves time, memory and trace space. -static void MapRodata() { +static NOINLINE void MapRodata(char* buffer, uptr size) { // First create temp file. const char *tmpdir = GetEnv("TMPDIR"); if (tmpdir == 0) @@ -163,13 +163,12 @@ static void MapRodata() { #endif if (tmpdir == 0) return; - char name[256]; - internal_snprintf(name, sizeof(name), "%s/tsan.rodata.%d", + internal_snprintf(buffer, size, "%s/tsan.rodata.%d", tmpdir, (int)internal_getpid()); - uptr openrv = internal_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + uptr openrv = internal_open(buffer, O_RDWR | O_CREAT | O_EXCL, 0600); if (internal_iserror(openrv)) return; - internal_unlink(name); // Unlink it now, so that we can reuse the buffer. + internal_unlink(buffer); // Unlink it now, so that we can reuse the buffer. fd_t fd = openrv; // Fill the file with Shadow::kRodata. const uptr kMarkerSize = 512 * 1024 / sizeof(RawShadow); @@ -188,8 +187,8 @@ static void MapRodata() { } // Map the file into shadow of .rodata sections. MemoryMappingLayout proc_maps(/*cache_enabled*/true); - // Reusing the buffer 'name'. - MemoryMappedSegment segment(name, ARRAY_SIZE(name)); + // Reusing the buffer 'buffer'. + MemoryMappedSegment segment(buffer, size); while (proc_maps.Next(&segment)) { if (segment.filename[0] != 0 && segment.filename[0] != '[' && segment.IsReadable() && segment.IsExecutable() && @@ -209,7 +208,8 @@ static void MapRodata() { } void InitializeShadowMemoryPlatform() { - MapRodata(); + char buffer[256]; // Keep in a different frame. + MapRodata(buffer, sizeof(buffer)); } #endif // #if !SANITIZER_GO @@ -267,7 +267,17 @@ void InitializePlatformEarly() { Die(); } # endif -#endif +# elif SANITIZER_RISCV64 + // the bottom half of vma is allocated for userspace + vmaSize = vmaSize + 1; +# if !SANITIZER_GO + if (vmaSize != 39 && vmaSize != 48) { + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); + Printf("FATAL: Found %zd - Supported 39 and 48\n", vmaSize); + Die(); + } +# endif +# endif } void InitializePlatform() { @@ -399,13 +409,15 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) { return mangled_sp ^ xor_key; #elif defined(__mips__) return mangled_sp; -#elif defined(__s390x__) +# elif SANITIZER_RISCV64 + return mangled_sp; +# elif defined(__s390x__) // tcbhead_t.stack_guard uptr xor_key = ((uptr *)__builtin_thread_pointer())[5]; return mangled_sp ^ xor_key; -#else - #error "Unknown platform" -#endif +# else +# error "Unknown platform" +# endif } #if SANITIZER_NETBSD @@ -429,11 +441,13 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) { # define LONG_JMP_SP_ENV_SLOT 1 # elif defined(__mips64) # define LONG_JMP_SP_ENV_SLOT 1 -# elif defined(__s390x__) -# define LONG_JMP_SP_ENV_SLOT 9 -# else -# define LONG_JMP_SP_ENV_SLOT 6 -# endif +# elif SANITIZER_RISCV64 +# define LONG_JMP_SP_ENV_SLOT 13 +# elif defined(__s390x__) +# define LONG_JMP_SP_ENV_SLOT 9 +# else +# define LONG_JMP_SP_ENV_SLOT 6 +# endif #endif uptr ExtractLongJmpSp(uptr *env) { diff --git a/libsanitizer/tsan/tsan_report.cpp b/libsanitizer/tsan/tsan_report.cpp index 9b03adc..35cb671 100644 --- a/libsanitizer/tsan/tsan_report.cpp +++ b/libsanitizer/tsan/tsan_report.cpp @@ -93,17 +93,13 @@ static const char *ReportTypeString(ReportType typ, uptr tag) { return "signal handler spoils errno"; case ReportTypeDeadlock: return "lock-order-inversion (potential deadlock)"; - // No default case so compiler warns us if we miss one + case ReportTypeMutexHeldWrongContext: + return "mutex held in the wrong context"; + // No default case so compiler warns us if we miss one } UNREACHABLE("missing case"); } -#if SANITIZER_APPLE -static const char *const kInterposedFunctionPrefix = "wrap_"; -#else -static const char *const kInterposedFunctionPrefix = "__interceptor_"; -#endif - void PrintStack(const ReportStack *ent) { if (ent == 0 || ent->frames == 0) { Printf(" [failed to restore the stack]\n\n"); @@ -112,10 +108,10 @@ void PrintStack(const ReportStack *ent) { SymbolizedStack *frame = ent->frames; for (int i = 0; frame && frame->info.address; frame = frame->next, i++) { InternalScopedString res; - RenderFrame(&res, common_flags()->stack_trace_format, i, - frame->info.address, &frame->info, - common_flags()->symbolize_vs_style, - common_flags()->strip_path_prefix, kInterposedFunctionPrefix); + StackTracePrinter::GetOrInit()->RenderFrame( + &res, common_flags()->stack_trace_format, i, frame->info.address, + &frame->info, common_flags()->symbolize_vs_style, + common_flags()->strip_path_prefix); Printf("%s\n", res.data()); } Printf("\n"); @@ -284,6 +280,7 @@ static bool FrameIsInternal(const SymbolizedStack *frame) { const char *module = frame->info.module; if (file != 0 && (internal_strstr(file, "tsan_interceptors_posix.cpp") || + internal_strstr(file, "tsan_interceptors_memintrinsics.cpp") || internal_strstr(file, "sanitizer_common_interceptors.inc") || internal_strstr(file, "tsan_interface_"))) return true; diff --git a/libsanitizer/tsan/tsan_report.h b/libsanitizer/tsan/tsan_report.h index 3c88864..bfe4707 100644 --- a/libsanitizer/tsan/tsan_report.h +++ b/libsanitizer/tsan/tsan_report.h @@ -34,7 +34,8 @@ enum ReportType { ReportTypeMutexBadReadUnlock, ReportTypeSignalUnsafe, ReportTypeErrnoInSignal, - ReportTypeDeadlock + ReportTypeDeadlock, + ReportTypeMutexHeldWrongContext }; struct ReportStack { diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp index 6b1ec1d..fd9441d 100644 --- a/libsanitizer/tsan/tsan_rtl.cpp +++ b/libsanitizer/tsan/tsan_rtl.cpp @@ -446,7 +446,7 @@ static bool InitializeMemoryProfiler() { ctx->memprof_fd = 2; } else { InternalScopedString filename; - filename.append("%s.%d", fname, (int)internal_getpid()); + filename.AppendF("%s.%d", fname, (int)internal_getpid()); ctx->memprof_fd = OpenFile(filename.data(), WrOnly); if (ctx->memprof_fd == kInvalidFd) { Printf("ThreadSanitizer: failed to open memory profile file '%s'\n", diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h index a5606db..de4ea0b 100644 --- a/libsanitizer/tsan/tsan_rtl.h +++ b/libsanitizer/tsan/tsan_rtl.h @@ -56,8 +56,8 @@ namespace __tsan { #if !SANITIZER_GO struct MapUnmapCallback; -#if defined(__mips64) || defined(__aarch64__) || defined(__loongarch__) || \ - defined(__powerpc__) +# if defined(__mips64) || defined(__aarch64__) || defined(__loongarch__) || \ + defined(__powerpc__) || SANITIZER_RISCV64 struct AP32 { static const uptr kSpaceBeg = 0; diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S index 9e533a7..8285e21 100644 --- a/libsanitizer/tsan/tsan_rtl_ppc64.S +++ b/libsanitizer/tsan/tsan_rtl_ppc64.S @@ -1,6 +1,5 @@ #include "tsan_ppc_regs.h" - .machine altivec .section .text .hidden __tsan_setjmp .globl _setjmp diff --git a/libsanitizer/tsan/tsan_rtl_riscv64.S b/libsanitizer/tsan/tsan_rtl_riscv64.S new file mode 100644 index 0000000..8e6b9b9 --- /dev/null +++ b/libsanitizer/tsan/tsan_rtl_riscv64.S @@ -0,0 +1,203 @@ +#include "sanitizer_common/sanitizer_asm.h" + +.section .text + +.comm _ZN14__interception11real_setjmpE,8,8 +.globl ASM_SYMBOL_INTERCEPTOR(setjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(setjmp)) +ASM_SYMBOL_INTERCEPTOR(setjmp): + CFI_STARTPROC + + // Save frame pointer and return address register + addi sp, sp, -32 + sd ra, 24(sp) + sd s0, 16(sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (1, -8) + CFI_OFFSET (8, -16) + + // Adjust the SP for previous frame + addi s0, sp, 32 + CFI_DEF_CFA_REGISTER (8) + + // Save env parameter + sd a0, 8(sp) + CFI_OFFSET (10, -24) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + addi a0, s0, 0 + + // call tsan interceptor + call ASM_SYMBOL(__tsan_setjmp) + + // Restore env parameter + ld a0, 8(sp) + CFI_RESTORE (10) + + // Restore frame/link register + ld s0, 16(sp) + ld ra, 24(sp) + addi sp, sp, 32 + CFI_RESTORE (8) + CFI_RESTORE (1) + CFI_DEF_CFA (2, 0) + + // tail jump to libc setjmp + la t1, _ZN14__interception11real_setjmpE + ld t1, 0(t1) + jr t1 + + CFI_ENDPROC +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(setjmp)) + +.comm _ZN14__interception12real__setjmpE,8,8 +.globl ASM_SYMBOL_INTERCEPTOR(_setjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(_setjmp)) +ASM_SYMBOL_INTERCEPTOR(_setjmp): + CFI_STARTPROC + + // Save frame pointer and return address register + addi sp, sp, -32 + sd ra, 24(sp) + sd s0, 16(sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (1, -8) + CFI_OFFSET (8, -16) + + // Adjust the SP for previous frame + addi s0, sp, 32 + CFI_DEF_CFA_REGISTER (8) + + // Save env parameter + sd a0, 8(sp) + CFI_OFFSET (10, -24) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + addi a0, s0, 0 + + // call tsan interceptor + call ASM_SYMBOL(__tsan_setjmp) + + // Restore env parameter + ld a0, 8(sp) + CFI_RESTORE (10) + + // Restore frame/link register + ld s0, 16(sp) + ld ra, 24(sp) + addi sp, sp, 32 + CFI_RESTORE (8) + CFI_RESTORE (1) + CFI_DEF_CFA (2, 0) + + // tail jump to libc setjmp + la t1, _ZN14__interception12real__setjmpE + ld t1, 0(t1) + jr t1 + + CFI_ENDPROC +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(_setjmp)) + +.comm _ZN14__interception14real_sigsetjmpE,8,8 +.globl ASM_SYMBOL_INTERCEPTOR(sigsetjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(sigsetjmp)) +ASM_SYMBOL_INTERCEPTOR(sigsetjmp): + CFI_STARTPROC + + // Save frame pointer and return address register + addi sp, sp, -32 + sd ra, 24(sp) + sd s0, 16(sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (1, -8) + CFI_OFFSET (8, -16) + + // Adjust the SP for previous frame + addi s0, sp, 32 + CFI_DEF_CFA_REGISTER (8) + + // Save env parameter + sd a0, 8(sp) + sd a1, 0(sp) + CFI_OFFSET (10, -24) + CFI_OFFSET (11, -32) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + addi a0, s0, 0 + + // call tsan interceptor + call ASM_SYMBOL(__tsan_setjmp) + + // Restore env parameter + ld a0, 8(sp) + ld a1, 0(sp) + CFI_RESTORE (10) + CFI_RESTORE (11) + + // Restore frame/link register + ld s0, 16(sp) + ld ra, 24(sp) + addi sp, sp, 32 + CFI_RESTORE (8) + CFI_RESTORE (1) + CFI_DEF_CFA (2, 0) + + // tail jump to libc setjmp + la t1, _ZN14__interception14real_sigsetjmpE + ld t1, 0(t1) + jr t1 + + CFI_ENDPROC +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(sigsetjmp)) + +.comm _ZN14__interception16real___sigsetjmpE,8,8 +.globl ASM_SYMBOL_INTERCEPTOR(__sigsetjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) +ASM_SYMBOL_INTERCEPTOR(__sigsetjmp): + CFI_STARTPROC + + // Save frame pointer and return address register + addi sp, sp, -32 + sd ra, 24(sp) + sd s0, 16(sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (1, -8) + CFI_OFFSET (8, -16) + + // Adjust the SP for previous frame + addi s0, sp, 32 + CFI_DEF_CFA_REGISTER (8) + + // Save env parameter + sd a0, 8(sp) + sd a1, 0(sp) + CFI_OFFSET (10, -24) + CFI_OFFSET (11, -32) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + addi a0, s0, 0 + + // call tsan interceptor + call ASM_SYMBOL(__tsan_setjmp) + + // Restore env parameter + ld a0, 8(sp) + ld a1, 0(sp) + CFI_RESTORE (10) + CFI_RESTORE (11) + + // Restore frame/link register + ld s0, 16(sp) + ld ra, 24(sp) + addi sp, sp, 32 + CFI_RESTORE (8) + CFI_RESTORE (1) + CFI_DEF_CFA (2, 0) + + // tail jump to libc setjmp + la t1, _ZN14__interception16real___sigsetjmpE + ld t1, 0(t1) + jr t1 + + CFI_ENDPROC +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) diff --git a/libsanitizer/tsan/tsan_suppressions.cpp b/libsanitizer/tsan/tsan_suppressions.cpp index 9cdfa32..7064212 100644 --- a/libsanitizer/tsan/tsan_suppressions.cpp +++ b/libsanitizer/tsan/tsan_suppressions.cpp @@ -81,6 +81,7 @@ static const char *conv(ReportType typ) { case ReportTypeMutexBadUnlock: case ReportTypeMutexBadReadLock: case ReportTypeMutexBadReadUnlock: + case ReportTypeMutexHeldWrongContext: return kSuppressionMutex; case ReportTypeSignalUnsafe: case ReportTypeErrnoInSignal: |