diff options
Diffstat (limited to 'compiler-rt')
-rw-r--r-- | compiler-rt/lib/builtins/cpu_model/aarch64.c | 11 | ||||
-rw-r--r-- | compiler-rt/lib/builtins/cpu_model/aarch64/hwcap.inc | 5 | ||||
-rw-r--r-- | compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/android.inc | 1 | ||||
-rw-r--r-- | compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/getauxval.inc | 2 | ||||
-rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp | 10 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_flags.cpp | 37 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_flags.h | 8 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_flags.inc | 12 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_interceptors.h | 10 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp | 11 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl.cpp | 14 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl.h | 4 | ||||
-rw-r--r-- | compiler-rt/test/tsan/Darwin/write-interpose.c | 50 |
13 files changed, 161 insertions, 14 deletions
diff --git a/compiler-rt/lib/builtins/cpu_model/aarch64.c b/compiler-rt/lib/builtins/cpu_model/aarch64.c index be29c90..06bc7c4a 100644 --- a/compiler-rt/lib/builtins/cpu_model/aarch64.c +++ b/compiler-rt/lib/builtins/cpu_model/aarch64.c @@ -32,19 +32,21 @@ typedef struct __ifunc_arg_t { _Bool __aarch64_have_lse_atomics __attribute__((visibility("hidden"), nocommon)) = false; +// The formatter wants to re-order these includes, but doing so is incorrect: +// clang-format off #if defined(__FreeBSD__) || defined(__OpenBSD__) -// clang-format off: should not reorder sys/auxv.h alphabetically #include <sys/auxv.h> -// clang-format on #include "aarch64/hwcap.inc" #include "aarch64/lse_atomics/elf_aux_info.inc" #elif defined(__Fuchsia__) #include "aarch64/hwcap.inc" #include "aarch64/lse_atomics/fuchsia.inc" #elif defined(__ANDROID__) +#include <sys/auxv.h> #include "aarch64/hwcap.inc" #include "aarch64/lse_atomics/android.inc" -#elif defined(__linux__) && __has_include(<sys/auxv.h>) +#elif defined(__linux__) +#include <sys/auxv.h> #include "aarch64/hwcap.inc" #include "aarch64/lse_atomics/getauxval.inc" #elif defined(_WIN32) @@ -52,6 +54,7 @@ _Bool __aarch64_have_lse_atomics #else // When unimplemented, we leave __aarch64_have_lse_atomics initialized to false. #endif +// clang-format on #if !defined(DISABLE_AARCH64_FMV) @@ -74,7 +77,7 @@ struct { #elif defined(__ANDROID__) #include "aarch64/fmv/hwcap.inc" #include "aarch64/fmv/android.inc" -#elif defined(__linux__) && __has_include(<sys/auxv.h>) +#elif defined(__linux__) #include "aarch64/fmv/hwcap.inc" #include "aarch64/fmv/getauxval.inc" #elif defined(_WIN32) diff --git a/compiler-rt/lib/builtins/cpu_model/aarch64/hwcap.inc b/compiler-rt/lib/builtins/cpu_model/aarch64/hwcap.inc index 159c617..1c53191 100644 --- a/compiler-rt/lib/builtins/cpu_model/aarch64/hwcap.inc +++ b/compiler-rt/lib/builtins/cpu_model/aarch64/hwcap.inc @@ -1,8 +1,3 @@ -#if __has_include(<sys/hwcap.h>) -#include <sys/hwcap.h> -#define HAVE_SYS_HWCAP_H -#endif - #ifndef _IFUNC_ARG_HWCAP #define _IFUNC_ARG_HWCAP (1ULL << 62) #endif diff --git a/compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/android.inc b/compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/android.inc index 94bf64a..8d8a913 100644 --- a/compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/android.inc +++ b/compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/android.inc @@ -1,5 +1,4 @@ #include <string.h> -#include <sys/auxv.h> #include <sys/system_properties.h> static bool __isExynos9810(void) { diff --git a/compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/getauxval.inc b/compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/getauxval.inc index 6642c1f..670aba5 100644 --- a/compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/getauxval.inc +++ b/compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/getauxval.inc @@ -1,5 +1,3 @@ -#include <sys/auxv.h> - static void CONSTRUCTOR_ATTRIBUTE init_have_lse_atomics(void) { unsigned long hwcap = getauxval(AT_HWCAP); __aarch64_have_lse_atomics = (hwcap & HWCAP_ATOMICS) != 0; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp index 721c39d..0040f79 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -105,6 +105,10 @@ extern "C" { mach_msg_type_number_t *infoCnt); } +// Weak symbol no-op when TSan is not linked +SANITIZER_WEAK_ATTRIBUTE extern void __tsan_set_in_internal_write_call( + bool value) {} + namespace __sanitizer { #include "sanitizer_syscall_generic.inc" @@ -175,7 +179,11 @@ uptr internal_read(fd_t fd, void *buf, uptr count) { } uptr internal_write(fd_t fd, const void *buf, uptr count) { - return write(fd, buf, count); + // We need to disable interceptors when writing in TSan + __tsan_set_in_internal_write_call(true); + uptr res = write(fd, buf, count); + __tsan_set_in_internal_write_call(false); + return res; } uptr internal_stat(const char *path, void *buf) { diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.cpp b/compiler-rt/lib/tsan/rtl/tsan_flags.cpp index 3fd58f4..50632d2 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_flags.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_flags.cpp @@ -20,6 +20,43 @@ #include "tsan_rtl.h" #include "ubsan/ubsan_flags.h" +#if SANITIZER_APPLE +namespace __sanitizer { + +template <> +inline bool FlagHandler<LockDuringWriteSetting>::Parse(const char *value) { + if (internal_strcmp(value, "on") == 0) { + *t_ = kLockDuringAllWrites; + return true; + } + if (internal_strcmp(value, "disable_for_current_process") == 0) { + *t_ = kNoLockDuringWritesCurrentProcess; + return true; + } + if (internal_strcmp(value, "disable_for_all_processes") == 0) { + *t_ = kNoLockDuringWritesAllProcesses; + return true; + } + Printf("ERROR: Invalid value for signal handler option: '%s'\n", value); + return false; +} + +template <> +inline bool FlagHandler<LockDuringWriteSetting>::Format(char *buffer, + uptr size) { + switch (*t_) { + case kLockDuringAllWrites: + return FormatString(buffer, size, "on"); + case kNoLockDuringWritesCurrentProcess: + return FormatString(buffer, size, "disable_for_current_process"); + case kNoLockDuringWritesAllProcesses: + return FormatString(buffer, size, "disable_for_all_processes"); + } +} + +} // namespace __sanitizer +#endif + namespace __tsan { // Can be overriden in frontend. diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.h b/compiler-rt/lib/tsan/rtl/tsan_flags.h index da27d5b..477d08d 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_flags.h +++ b/compiler-rt/lib/tsan/rtl/tsan_flags.h @@ -16,6 +16,14 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_deadlock_detector_interface.h" +#if SANITIZER_APPLE +enum LockDuringWriteSetting { + kLockDuringAllWrites, + kNoLockDuringWritesCurrentProcess, + kNoLockDuringWritesAllProcesses, +}; +#endif + namespace __tsan { struct Flags : DDFlags { diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.inc b/compiler-rt/lib/tsan/rtl/tsan_flags.inc index 731d776..64cc091 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_flags.inc +++ b/compiler-rt/lib/tsan/rtl/tsan_flags.inc @@ -80,3 +80,15 @@ TSAN_FLAG(bool, shared_ptr_interceptor, true, TSAN_FLAG(bool, print_full_thread_history, false, "If set, prints thread creation stacks for the threads involved in " "the report and their ancestors up to the main thread.") + +#if SANITIZER_APPLE +TSAN_FLAG(LockDuringWriteSetting, lock_during_write, kLockDuringAllWrites, + "Determines whether to obtain a lock while writing logs or error " + "reports. " + "\"on\" - [default] lock during all writes. " + "\"disable_for_current_process\" - don't lock during all writes in " + "the current process, but do lock for all writes in child " + "processes." + "\"disable_for_all_processes\" - don't lock during all writes in " + "the current process and it's children processes.") +#endif diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.h b/compiler-rt/lib/tsan/rtl/tsan_interceptors.h index a357a87..d4b65ab 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.h +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.h @@ -1,6 +1,9 @@ #ifndef TSAN_INTERCEPTORS_H #define TSAN_INTERCEPTORS_H +#if SANITIZER_APPLE +# include "sanitizer_common/sanitizer_mac.h" +#endif #include "sanitizer_common/sanitizer_stacktrace.h" #include "tsan_rtl.h" @@ -43,7 +46,12 @@ inline bool in_symbolizer() { #endif inline bool MustIgnoreInterceptor(ThreadState *thr) { - return !thr->is_inited || thr->ignore_interceptors || thr->in_ignored_lib; + return !thr->is_inited || thr->ignore_interceptors || thr->in_ignored_lib +#if SANITIZER_APPLE + || (flags()->lock_during_write != kLockDuringAllWrites && + thr->in_internal_write_call) +#endif + ; } } // namespace __tsan diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp index 37c69b1..0c35804 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp @@ -31,6 +31,9 @@ #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "sanitizer_common/sanitizer_vector.h" #include "tsan_fd.h" +#if SANITIZER_APPLE +# include "tsan_flags.h" +#endif #include "tsan_interceptors.h" #include "tsan_interface.h" #include "tsan_mman.h" @@ -1665,6 +1668,14 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) { TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) { SCOPED_INTERCEPTOR_RAW(pthread_once, o, f); +#if SANITIZER_APPLE + if (flags()->lock_during_write != kLockDuringAllWrites && + cur_thread_init()->in_internal_write_call) { + // This is needed to make it through process launch without hanging + f(); + return 0; + } +#endif if (o == 0 || f == 0) return errno_EINVAL; atomic_uint32_t *a; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp index 0d7247a..b8041d7 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp @@ -40,6 +40,13 @@ SANITIZER_WEAK_DEFAULT_IMPL void __tsan_test_only_on_fork() {} #endif +#if SANITIZER_APPLE +// Override weak symbol from sanitizer_common +extern void __tsan_set_in_internal_write_call(bool value) { + __tsan::cur_thread_init()->in_internal_write_call = value; +} +#endif + namespace __tsan { #if !SANITIZER_GO @@ -893,6 +900,13 @@ void ForkChildAfter(ThreadState* thr, uptr pc, bool start_thread) { ThreadIgnoreBegin(thr, pc); ThreadIgnoreSyncBegin(thr, pc); } + +# if SANITIZER_APPLE + // This flag can have inheritance disabled - we are the child so act + // accordingly + if (flags()->lock_during_write == kNoLockDuringWritesCurrentProcess) + flags()->lock_during_write = kLockDuringAllWrites; +# endif } #endif diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h index 0b6d5f0..77390f0 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -236,6 +236,10 @@ struct alignas(SANITIZER_CACHE_LINE_SIZE) ThreadState { const ReportDesc *current_report; +#if SANITIZER_APPLE + bool in_internal_write_call; +#endif + explicit ThreadState(Tid tid); }; diff --git a/compiler-rt/test/tsan/Darwin/write-interpose.c b/compiler-rt/test/tsan/Darwin/write-interpose.c new file mode 100644 index 0000000..cbd9a08 --- /dev/null +++ b/compiler-rt/test/tsan/Darwin/write-interpose.c @@ -0,0 +1,50 @@ +// Test that dylibs interposing write, and then calling functions intercepted +// by TSan don't deadlock (self-lock) + +// RUN: %clang_tsan %s -o %t +// RUN: %clang_tsan %s -o %t.dylib -fno-sanitize=thread -dynamiclib -DSHARED_LIB + +// Note that running the below command with out `lock_during_write` should +// deadlock (self-lock) +// RUN: env DYLD_INSERT_LIBRARIES=%t.dylib TSAN_OPTIONS=verbosity=2:lock_during_write=disable_for_current_process %run %t 2>&1 | FileCheck %s + +#include <stdio.h> + +#if defined(SHARED_LIB) + +// dylib implementation - interposes write() calls +# include <os/lock.h> +# include <unistd.h> + +struct interpose_substitution { + const void *replacement; + const void *original; +}; + +# define INTERPOSE(replacement, original) \ + __attribute__((used)) static const struct interpose_substitution \ + substitution_##original[] \ + __attribute__((section("__DATA, __interpose"))) = { \ + {(const void *)(replacement), (const void *)(original)}} + +static ssize_t my_write(int fd, const void *buf, size_t count) { + struct os_unfair_lock_s lock = OS_UNFAIR_LOCK_INIT; + os_unfair_lock_lock(&lock); + printf("Interposed write called: fd=%d, count=%zu\n", fd, count); + ssize_t res = write(fd, buf, count); + os_unfair_lock_unlock(&lock); + return res; +} +INTERPOSE(my_write, write); + +#else // defined(SHARED_LIB) + +int main() { + printf("Write test completed\n"); + return 0; +} + +#endif // defined(SHARED_LIB) + +// CHECK: Interposed write called: fd={{[0-9]+}}, count={{[0-9]+}} +// CHECK: Write test completed |