aboutsummaryrefslogtreecommitdiff
path: root/compiler-rt
diff options
context:
space:
mode:
Diffstat (limited to 'compiler-rt')
-rw-r--r--compiler-rt/lib/builtins/cpu_model/aarch64.c11
-rw-r--r--compiler-rt/lib/builtins/cpu_model/aarch64/hwcap.inc5
-rw-r--r--compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/android.inc1
-rw-r--r--compiler-rt/lib/builtins/cpu_model/aarch64/lse_atomics/getauxval.inc2
-rw-r--r--compiler-rt/lib/orc/coff_platform.cpp72
-rw-r--r--compiler-rt/lib/orc/coff_platform.h1
-rw-r--r--compiler-rt/lib/orc/dlfcn_wrapper.cpp2
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp10
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_flags.cpp37
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_flags.h8
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_flags.inc12
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_interceptors.h10
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp11
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.cpp14
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.h4
-rw-r--r--compiler-rt/test/tsan/Darwin/write-interpose.c50
16 files changed, 234 insertions, 16 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/orc/coff_platform.cpp b/compiler-rt/lib/orc/coff_platform.cpp
index 78144ec..4cce20e 100644
--- a/compiler-rt/lib/orc/coff_platform.cpp
+++ b/compiler-rt/lib/orc/coff_platform.cpp
@@ -110,6 +110,7 @@ public:
const char *dlerror();
void *dlopen(std::string_view Name, int Mode);
+ int dlupdate(void *DSOHandle);
int dlclose(void *Header);
void *dlsym(void *Header, std::string_view Symbol);
@@ -141,6 +142,10 @@ private:
Error dlopenFull(JITDylibState &JDS);
Error dlopenInitialize(JITDylibState &JDS, COFFJITDylibDepInfoMap &DepInfo);
+ Error dlupdateImpl(void *DSOHandle);
+ Error dlupdateFull(JITDylibState &JDS);
+ Error dlupdateInitialize(JITDylibState &JDS);
+
Error dlcloseImpl(void *DSOHandle);
Error dlcloseDeinitialize(JITDylibState &JDS);
@@ -265,6 +270,20 @@ void *COFFPlatformRuntimeState::dlopen(std::string_view Path, int Mode) {
}
}
+int COFFPlatformRuntimeState::dlupdate(void *DSOHandle) {
+ ORC_RT_DEBUG({
+ std::string S;
+ printdbg("COFFPlatform::dlupdate(%p) (%s)\n", DSOHandle, S.c_str());
+ });
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ if (auto Err = dlupdateImpl(DSOHandle)) {
+ // FIXME: Make dlerror thread safe.
+ DLFcnError = toString(std::move(Err));
+ return -1;
+ }
+ return 0;
+}
+
int COFFPlatformRuntimeState::dlclose(void *DSOHandle) {
ORC_RT_DEBUG({
auto *JDS = getJITDylibStateByHeader(DSOHandle);
@@ -390,6 +409,55 @@ Error COFFPlatformRuntimeState::dlopenInitialize(
return Error::success();
}
+Error COFFPlatformRuntimeState::dlupdateImpl(void *DSOHandle) {
+ // Try to find JITDylib state by header.
+ auto *JDS = getJITDylibStateByHeader(DSOHandle);
+
+ if (!JDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "No registered JITDylib for " << DSOHandle;
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ if (!JDS->referenced())
+ return make_error<StringError>("dlupdate failed, JITDylib must be open.");
+
+ if (auto Err = dlupdateFull(*JDS))
+ return Err;
+
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::dlupdateFull(JITDylibState &JDS) {
+ // Call back to the JIT to push the initializers.
+ Expected<COFFJITDylibDepInfoMap> DepInfoMap((COFFJITDylibDepInfoMap()));
+ if (auto Err = WrapperFunction<SPSExpected<SPSCOFFJITDylibDepInfoMap>(
+ SPSExecutorAddr)>::
+ call(JITDispatch(&__orc_rt_coff_push_initializers_tag), DepInfoMap,
+ ExecutorAddr::fromPtr(JDS.Header)))
+ return Err;
+ if (!DepInfoMap)
+ return DepInfoMap.takeError();
+
+ if (auto Err = dlupdateInitialize(JDS))
+ return Err;
+
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::dlupdateInitialize(JITDylibState &JDS) {
+ ORC_RT_DEBUG({
+ printdbg("COFFPlatformRuntimeState::dlupdateInitialize(\"%s\")\n",
+ JDS.Name.c_str());
+ });
+
+ // Run static initializers.
+ JDS.CInitSection.RunAllNewAndFlush();
+ JDS.CXXInitSection.RunAllNewAndFlush();
+
+ return Error::success();
+}
+
Error COFFPlatformRuntimeState::dlcloseImpl(void *DSOHandle) {
// Try to find JITDylib state by header.
auto *JDS = getJITDylibStateByHeader(DSOHandle);
@@ -667,6 +735,10 @@ void *__orc_rt_coff_jit_dlopen(const char *path, int mode) {
return COFFPlatformRuntimeState::get().dlopen(path, mode);
}
+int __orc_rt_coff_jit_dlupdate(void *dso_handle) {
+ return COFFPlatformRuntimeState::get().dlupdate(dso_handle);
+}
+
int __orc_rt_coff_jit_dlclose(void *header) {
return COFFPlatformRuntimeState::get().dlclose(header);
}
diff --git a/compiler-rt/lib/orc/coff_platform.h b/compiler-rt/lib/orc/coff_platform.h
index aae57bc..e9891f0b 100644
--- a/compiler-rt/lib/orc/coff_platform.h
+++ b/compiler-rt/lib/orc/coff_platform.h
@@ -19,6 +19,7 @@
// dlfcn functions.
ORC_RT_INTERFACE const char *__orc_rt_coff_jit_dlerror();
ORC_RT_INTERFACE void *__orc_rt_coff_jit_dlopen(const char *path, int mode);
+ORC_RT_INTERFACE int __orc_rt_coff_jit_dlupdate(void *dso_handle);
ORC_RT_INTERFACE int __orc_rt_coff_jit_dlclose(void *header);
ORC_RT_INTERFACE void *__orc_rt_coff_jit_dlsym(void *header,
const char *symbol);
diff --git a/compiler-rt/lib/orc/dlfcn_wrapper.cpp b/compiler-rt/lib/orc/dlfcn_wrapper.cpp
index 02e3796..cb92a1f 100644
--- a/compiler-rt/lib/orc/dlfcn_wrapper.cpp
+++ b/compiler-rt/lib/orc/dlfcn_wrapper.cpp
@@ -42,7 +42,6 @@ __orc_rt_jit_dlopen_wrapper(const char *ArgData, size_t ArgSize) {
.release();
}
-#ifndef _WIN32
ORC_RT_INTERFACE orc_rt_WrapperFunctionResult
__orc_rt_jit_dlupdate_wrapper(const char *ArgData, size_t ArgSize) {
return WrapperFunction<int32_t(SPSExecutorAddr)>::handle(
@@ -52,7 +51,6 @@ __orc_rt_jit_dlupdate_wrapper(const char *ArgData, size_t ArgSize) {
})
.release();
}
-#endif
ORC_RT_INTERFACE orc_rt_WrapperFunctionResult
__orc_rt_jit_dlclose_wrapper(const char *ArgData, size_t ArgSize) {
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