aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/compiler-rt/lib/rtsan
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/compiler-rt/lib/rtsan')
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/rtsan.cpp50
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/rtsan.h47
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_context.cpp98
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_context.h38
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors.cpp442
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors.h15
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_preinit.cpp21
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_stack.cpp50
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_stack.h15
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_context.cpp69
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_functional.cpp207
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp516
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_main.cpp17
-rw-r--r--contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_utilities.h47
14 files changed, 1632 insertions, 0 deletions
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan.cpp b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan.cpp
new file mode 100644
index 000000000000..cf7fbddd9eb9
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan.cpp
@@ -0,0 +1,50 @@
+//===--- rtsan.cpp - Realtime Sanitizer -------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include <rtsan/rtsan.h>
+#include <rtsan/rtsan_context.h>
+#include <rtsan/rtsan_interceptors.h>
+
+using namespace __rtsan;
+
+bool __rtsan::rtsan_initialized;
+bool __rtsan::rtsan_init_is_running;
+
+extern "C" {
+
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() {
+ CHECK(!rtsan_init_is_running);
+ if (rtsan_initialized)
+ return;
+ rtsan_init_is_running = true;
+
+ InitializeInterceptors();
+
+ rtsan_init_is_running = false;
+ rtsan_initialized = true;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter() {
+ __rtsan::GetContextForThisThread().RealtimePush();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_exit() {
+ __rtsan::GetContextForThisThread().RealtimePop();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_off() {
+ __rtsan::GetContextForThisThread().BypassPush();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_on() {
+ __rtsan::GetContextForThisThread().BypassPop();
+}
+
+} // extern "C"
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan.h b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan.h
new file mode 100644
index 000000000000..ccddaf2c893e
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan.h
@@ -0,0 +1,47 @@
+//===--- rtsan.h - Realtime Sanitizer ---------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+extern "C" {
+
+namespace __rtsan {
+
+extern bool rtsan_initialized;
+extern bool rtsan_init_is_running;
+
+} // namespace __rtsan
+
+// Initialise rtsan interceptors.
+// A call to this method is added to the preinit array on Linux systems.
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init();
+
+// Enter real-time context.
+// When in a real-time context, RTSan interceptors will error if realtime
+// violations are detected. Calls to this method are injected at the code
+// generation stage when RTSan is enabled.
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter();
+
+// Exit the real-time context.
+// When not in a real-time context, RTSan interceptors will simply forward
+// intercepted method calls to the real methods.
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_exit();
+
+// Disable all RTSan error reporting.
+// Injected into the code if "nosanitize(realtime)" is on a function.
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_off();
+
+// Re-enable all RTSan error reporting.
+// The counterpart to `__rtsan_off`.
+SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_on();
+
+} // extern "C"
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_context.cpp b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_context.cpp
new file mode 100644
index 000000000000..f761ddedce67
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_context.cpp
@@ -0,0 +1,98 @@
+//===--- rtsan_context.cpp - Realtime Sanitizer -----------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include <rtsan/rtsan_context.h>
+
+#include <rtsan/rtsan_stack.h>
+
+#include <sanitizer_common/sanitizer_allocator_internal.h>
+#include <sanitizer_common/sanitizer_stacktrace.h>
+
+#include <new>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static pthread_key_t context_key;
+static pthread_once_t key_once = PTHREAD_ONCE_INIT;
+
+// InternalFree cannot be passed directly to pthread_key_create
+// because it expects a signature with only one arg
+static void InternalFreeWrapper(void *ptr) { __sanitizer::InternalFree(ptr); }
+
+static __rtsan::Context &GetContextForThisThreadImpl() {
+ auto make_thread_local_context_key = []() {
+ CHECK_EQ(pthread_key_create(&context_key, InternalFreeWrapper), 0);
+ };
+
+ pthread_once(&key_once, make_thread_local_context_key);
+ __rtsan::Context *current_thread_context =
+ static_cast<__rtsan::Context *>(pthread_getspecific(context_key));
+ if (current_thread_context == nullptr) {
+ current_thread_context = static_cast<__rtsan::Context *>(
+ __sanitizer::InternalAlloc(sizeof(__rtsan::Context)));
+ new (current_thread_context) __rtsan::Context();
+ pthread_setspecific(context_key, current_thread_context);
+ }
+
+ return *current_thread_context;
+}
+
+/*
+ This is a placeholder stub for a future feature that will allow
+ a user to configure RTSan's behaviour when a real-time safety
+ violation is detected. The RTSan developers intend for the
+ following choices to be made available, via a RTSAN_OPTIONS
+ environment variable, in a future PR:
+
+ i) exit,
+ ii) continue, or
+ iii) wait for user input from stdin.
+
+ Until then, and to keep the first PRs small, only the exit mode
+ is available.
+*/
+static void InvokeViolationDetectedAction() { exit(EXIT_FAILURE); }
+
+__rtsan::Context::Context() = default;
+
+void __rtsan::Context::RealtimePush() { realtime_depth++; }
+
+void __rtsan::Context::RealtimePop() { realtime_depth--; }
+
+void __rtsan::Context::BypassPush() { bypass_depth++; }
+
+void __rtsan::Context::BypassPop() { bypass_depth--; }
+
+void __rtsan::Context::ExpectNotRealtime(
+ const char *intercepted_function_name) {
+ if (InRealtimeContext() && !IsBypassed()) {
+ BypassPush();
+ PrintDiagnostics(intercepted_function_name);
+ InvokeViolationDetectedAction();
+ BypassPop();
+ }
+}
+
+bool __rtsan::Context::InRealtimeContext() const { return realtime_depth > 0; }
+
+bool __rtsan::Context::IsBypassed() const { return bypass_depth > 0; }
+
+void __rtsan::Context::PrintDiagnostics(const char *intercepted_function_name) {
+ fprintf(stderr,
+ "Real-time violation: intercepted call to real-time unsafe function "
+ "`%s` in real-time context! Stack trace:\n",
+ intercepted_function_name);
+ __rtsan::PrintStackTrace();
+}
+
+__rtsan::Context &__rtsan::GetContextForThisThread() {
+ return GetContextForThisThreadImpl();
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_context.h b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_context.h
new file mode 100644
index 000000000000..515bb8ade1eb
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_context.h
@@ -0,0 +1,38 @@
+//===--- rtsan_context.h - Realtime Sanitizer -------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+namespace __rtsan {
+
+class Context {
+public:
+ Context();
+
+ void RealtimePush();
+ void RealtimePop();
+
+ void BypassPush();
+ void BypassPop();
+
+ void ExpectNotRealtime(const char *intercepted_function_name);
+
+private:
+ bool InRealtimeContext() const;
+ bool IsBypassed() const;
+ void PrintDiagnostics(const char *intercepted_function_name);
+
+ int realtime_depth{0};
+ int bypass_depth{0};
+};
+
+Context &GetContextForThisThread();
+
+} // namespace __rtsan
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors.cpp b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
new file mode 100644
index 000000000000..b63040446e53
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
@@ -0,0 +1,442 @@
+//===--- rtsan_interceptors.cpp - Realtime Sanitizer ------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "rtsan/rtsan_interceptors.h"
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator_dlsym.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+
+#include "interception/interception.h"
+#include "rtsan/rtsan.h"
+#include "rtsan/rtsan_context.h"
+
+#if SANITIZER_APPLE
+
+#if TARGET_OS_MAC
+// On MacOS OSSpinLockLock is deprecated and no longer present in the headers,
+// but the symbol still exists on the system. Forward declare here so we
+// don't get compilation errors.
+#include <stdint.h>
+extern "C" {
+typedef int32_t OSSpinLock;
+void OSSpinLockLock(volatile OSSpinLock *__lock);
+}
+#endif
+
+#include <libkern/OSAtomic.h>
+#include <os/lock.h>
+#endif
+
+#if SANITIZER_INTERCEPT_MEMALIGN || SANITIZER_INTERCEPT_PVALLOC
+#include <malloc.h>
+#endif
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+
+using namespace __sanitizer;
+
+using __rtsan::rtsan_init_is_running;
+using __rtsan::rtsan_initialized;
+
+namespace {
+struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
+ static bool UseImpl() { return !rtsan_initialized; }
+};
+} // namespace
+
+void ExpectNotRealtime(const char *intercepted_function_name) {
+ __rtsan::GetContextForThisThread().ExpectNotRealtime(
+ intercepted_function_name);
+}
+
+// Filesystem
+
+INTERCEPTOR(int, open, const char *path, int oflag, ...) {
+ // TODO Establish whether we should intercept here if the flag contains
+ // O_NONBLOCK
+ ExpectNotRealtime("open");
+
+ va_list args;
+ va_start(args, oflag);
+ const mode_t mode = va_arg(args, int);
+ va_end(args);
+
+ const int result = REAL(open)(path, oflag, mode);
+ return result;
+}
+
+INTERCEPTOR(int, openat, int fd, const char *path, int oflag, ...) {
+ // TODO Establish whether we should intercept here if the flag contains
+ // O_NONBLOCK
+ ExpectNotRealtime("openat");
+
+ va_list args;
+ va_start(args, oflag);
+ mode_t mode = va_arg(args, int);
+ va_end(args);
+
+ const int result = REAL(openat)(fd, path, oflag, mode);
+ return result;
+}
+
+INTERCEPTOR(int, creat, const char *path, mode_t mode) {
+ // TODO Establish whether we should intercept here if the flag contains
+ // O_NONBLOCK
+ ExpectNotRealtime("creat");
+ const int result = REAL(creat)(path, mode);
+ return result;
+}
+
+INTERCEPTOR(int, fcntl, int filedes, int cmd, ...) {
+ ExpectNotRealtime("fcntl");
+
+ va_list args;
+ va_start(args, cmd);
+
+ // Following precedent here. The linux source (fcntl.c, do_fcntl) accepts the
+ // final argument in a variable that will hold the largest of the possible
+ // argument types (pointers and ints are typical in fcntl) It is then assumed
+ // that the implementation of fcntl will cast it properly depending on cmd.
+ //
+ // This is also similar to what is done in
+ // sanitizer_common/sanitizer_common_syscalls.inc
+ const unsigned long arg = va_arg(args, unsigned long);
+ int result = REAL(fcntl)(filedes, cmd, arg);
+
+ va_end(args);
+
+ return result;
+}
+
+INTERCEPTOR(int, close, int filedes) {
+ ExpectNotRealtime("close");
+ return REAL(close)(filedes);
+}
+
+INTERCEPTOR(FILE *, fopen, const char *path, const char *mode) {
+ ExpectNotRealtime("fopen");
+ return REAL(fopen)(path, mode);
+}
+
+INTERCEPTOR(size_t, fread, void *ptr, size_t size, size_t nitems,
+ FILE *stream) {
+ ExpectNotRealtime("fread");
+ return REAL(fread)(ptr, size, nitems, stream);
+}
+
+INTERCEPTOR(size_t, fwrite, const void *ptr, size_t size, size_t nitems,
+ FILE *stream) {
+ ExpectNotRealtime("fwrite");
+ return REAL(fwrite)(ptr, size, nitems, stream);
+}
+
+INTERCEPTOR(int, fclose, FILE *stream) {
+ ExpectNotRealtime("fclose");
+ return REAL(fclose)(stream);
+}
+
+INTERCEPTOR(int, fputs, const char *s, FILE *stream) {
+ ExpectNotRealtime("fputs");
+ return REAL(fputs)(s, stream);
+}
+
+// Streams
+INTERCEPTOR(int, puts, const char *s) {
+ ExpectNotRealtime("puts");
+ return REAL(puts)(s);
+}
+
+// Concurrency
+#if SANITIZER_APPLE
+#pragma clang diagnostic push
+// OSSpinLockLock is deprecated, but still in use in libc++
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+INTERCEPTOR(void, OSSpinLockLock, volatile OSSpinLock *lock) {
+ ExpectNotRealtime("OSSpinLockLock");
+ return REAL(OSSpinLockLock)(lock);
+}
+#pragma clang diagnostic pop
+
+INTERCEPTOR(void, os_unfair_lock_lock, os_unfair_lock_t lock) {
+ ExpectNotRealtime("os_unfair_lock_lock");
+ return REAL(os_unfair_lock_lock)(lock);
+}
+#elif SANITIZER_LINUX
+INTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *spinlock) {
+ ExpectNotRealtime("pthread_spin_lock");
+ return REAL(pthread_spin_lock)(spinlock);
+}
+#endif
+
+INTERCEPTOR(int, pthread_create, pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg) {
+ ExpectNotRealtime("pthread_create");
+ return REAL(pthread_create)(thread, attr, start_routine, arg);
+}
+
+INTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *mutex) {
+ ExpectNotRealtime("pthread_mutex_lock");
+ return REAL(pthread_mutex_lock)(mutex);
+}
+
+INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *mutex) {
+ ExpectNotRealtime("pthread_mutex_unlock");
+ return REAL(pthread_mutex_unlock)(mutex);
+}
+
+INTERCEPTOR(int, pthread_join, pthread_t thread, void **value_ptr) {
+ ExpectNotRealtime("pthread_join");
+ return REAL(pthread_join)(thread, value_ptr);
+}
+
+INTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *cond) {
+ ExpectNotRealtime("pthread_cond_signal");
+ return REAL(pthread_cond_signal)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *cond) {
+ ExpectNotRealtime("pthread_cond_broadcast");
+ return REAL(pthread_cond_broadcast)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *cond,
+ pthread_mutex_t *mutex) {
+ ExpectNotRealtime("pthread_cond_wait");
+ return REAL(pthread_cond_wait)(cond, mutex);
+}
+
+INTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *cond,
+ pthread_mutex_t *mutex, const timespec *ts) {
+ ExpectNotRealtime("pthread_cond_timedwait");
+ return REAL(pthread_cond_timedwait)(cond, mutex, ts);
+}
+
+INTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *lock) {
+ ExpectNotRealtime("pthread_rwlock_rdlock");
+ return REAL(pthread_rwlock_rdlock)(lock);
+}
+
+INTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *lock) {
+ ExpectNotRealtime("pthread_rwlock_unlock");
+ return REAL(pthread_rwlock_unlock)(lock);
+}
+
+INTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *lock) {
+ ExpectNotRealtime("pthread_rwlock_wrlock");
+ return REAL(pthread_rwlock_wrlock)(lock);
+}
+
+// Sleeping
+
+INTERCEPTOR(unsigned int, sleep, unsigned int s) {
+ ExpectNotRealtime("sleep");
+ return REAL(sleep)(s);
+}
+
+INTERCEPTOR(int, usleep, useconds_t u) {
+ ExpectNotRealtime("usleep");
+ return REAL(usleep)(u);
+}
+
+INTERCEPTOR(int, nanosleep, const struct timespec *rqtp,
+ struct timespec *rmtp) {
+ ExpectNotRealtime("nanosleep");
+ return REAL(nanosleep)(rqtp, rmtp);
+}
+
+// Memory
+
+INTERCEPTOR(void *, calloc, SIZE_T num, SIZE_T size) {
+ if (DlsymAlloc::Use())
+ return DlsymAlloc::Callocate(num, size);
+
+ ExpectNotRealtime("calloc");
+ return REAL(calloc)(num, size);
+}
+
+INTERCEPTOR(void, free, void *ptr) {
+ if (DlsymAlloc::PointerIsMine(ptr))
+ return DlsymAlloc::Free(ptr);
+
+ if (ptr != NULL) {
+ ExpectNotRealtime("free");
+ }
+ return REAL(free)(ptr);
+}
+
+INTERCEPTOR(void *, malloc, SIZE_T size) {
+ if (DlsymAlloc::Use())
+ return DlsymAlloc::Allocate(size);
+
+ ExpectNotRealtime("malloc");
+ return REAL(malloc)(size);
+}
+
+INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
+ if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
+ return DlsymAlloc::Realloc(ptr, size);
+
+ ExpectNotRealtime("realloc");
+ return REAL(realloc)(ptr, size);
+}
+
+INTERCEPTOR(void *, reallocf, void *ptr, SIZE_T size) {
+ ExpectNotRealtime("reallocf");
+ return REAL(reallocf)(ptr, size);
+}
+
+INTERCEPTOR(void *, valloc, SIZE_T size) {
+ ExpectNotRealtime("valloc");
+ return REAL(valloc)(size);
+}
+
+#if SANITIZER_INTERCEPT_ALIGNED_ALLOC
+INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) {
+ ExpectNotRealtime("aligned_alloc");
+ return REAL(aligned_alloc)(alignment, size);
+}
+#define RTSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
+#else
+#define RTSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
+#endif
+
+INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
+ ExpectNotRealtime("posix_memalign");
+ return REAL(posix_memalign)(memptr, alignment, size);
+}
+
+#if SANITIZER_INTERCEPT_MEMALIGN
+INTERCEPTOR(void *, memalign, size_t alignment, size_t size) {
+ ExpectNotRealtime("memalign");
+ return REAL(memalign)(alignment, size);
+}
+#endif
+
+#if SANITIZER_INTERCEPT_PVALLOC
+INTERCEPTOR(void *, pvalloc, size_t size) {
+ ExpectNotRealtime("pvalloc");
+ return REAL(pvalloc)(size);
+}
+#endif
+
+// Sockets
+INTERCEPTOR(int, socket, int domain, int type, int protocol) {
+ ExpectNotRealtime("socket");
+ return REAL(socket)(domain, type, protocol);
+}
+
+INTERCEPTOR(ssize_t, send, int sockfd, const void *buf, size_t len, int flags) {
+ ExpectNotRealtime("send");
+ return REAL(send)(sockfd, buf, len, flags);
+}
+
+INTERCEPTOR(ssize_t, sendmsg, int socket, const struct msghdr *message,
+ int flags) {
+ ExpectNotRealtime("sendmsg");
+ return REAL(sendmsg)(socket, message, flags);
+}
+
+INTERCEPTOR(ssize_t, sendto, int socket, const void *buffer, size_t length,
+ int flags, const struct sockaddr *dest_addr, socklen_t dest_len) {
+ ExpectNotRealtime("sendto");
+ return REAL(sendto)(socket, buffer, length, flags, dest_addr, dest_len);
+}
+
+INTERCEPTOR(ssize_t, recv, int socket, void *buffer, size_t length, int flags) {
+ ExpectNotRealtime("recv");
+ return REAL(recv)(socket, buffer, length, flags);
+}
+
+INTERCEPTOR(ssize_t, recvfrom, int socket, void *buffer, size_t length,
+ int flags, struct sockaddr *address, socklen_t *address_len) {
+ ExpectNotRealtime("recvfrom");
+ return REAL(recvfrom)(socket, buffer, length, flags, address, address_len);
+}
+
+INTERCEPTOR(ssize_t, recvmsg, int socket, struct msghdr *message, int flags) {
+ ExpectNotRealtime("recvmsg");
+ return REAL(recvmsg)(socket, message, flags);
+}
+
+INTERCEPTOR(int, shutdown, int socket, int how) {
+ ExpectNotRealtime("shutdown");
+ return REAL(shutdown)(socket, how);
+}
+
+// Preinit
+void __rtsan::InitializeInterceptors() {
+ INTERCEPT_FUNCTION(calloc);
+ INTERCEPT_FUNCTION(free);
+ INTERCEPT_FUNCTION(malloc);
+ INTERCEPT_FUNCTION(realloc);
+ INTERCEPT_FUNCTION(reallocf);
+ INTERCEPT_FUNCTION(valloc);
+ RTSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
+ INTERCEPT_FUNCTION(posix_memalign);
+#if SANITIZER_INTERCEPT_MEMALIGN
+ INTERCEPT_FUNCTION(memalign);
+#endif
+#if SANITIZER_INTERCEPT_PVALLOC
+ INTERCEPT_FUNCTION(pvalloc);
+#endif
+
+ INTERCEPT_FUNCTION(open);
+ INTERCEPT_FUNCTION(openat);
+ INTERCEPT_FUNCTION(close);
+ INTERCEPT_FUNCTION(fopen);
+ INTERCEPT_FUNCTION(fread);
+ INTERCEPT_FUNCTION(fwrite);
+ INTERCEPT_FUNCTION(fclose);
+ INTERCEPT_FUNCTION(fcntl);
+ INTERCEPT_FUNCTION(creat);
+ INTERCEPT_FUNCTION(puts);
+ INTERCEPT_FUNCTION(fputs);
+
+#if SANITIZER_APPLE
+ INTERCEPT_FUNCTION(OSSpinLockLock);
+ INTERCEPT_FUNCTION(os_unfair_lock_lock);
+#elif SANITIZER_LINUX
+ INTERCEPT_FUNCTION(pthread_spin_lock);
+#endif
+
+ INTERCEPT_FUNCTION(pthread_create);
+ INTERCEPT_FUNCTION(pthread_mutex_lock);
+ INTERCEPT_FUNCTION(pthread_mutex_unlock);
+ INTERCEPT_FUNCTION(pthread_join);
+ INTERCEPT_FUNCTION(pthread_cond_signal);
+ INTERCEPT_FUNCTION(pthread_cond_broadcast);
+ INTERCEPT_FUNCTION(pthread_cond_wait);
+ INTERCEPT_FUNCTION(pthread_cond_timedwait);
+ INTERCEPT_FUNCTION(pthread_rwlock_rdlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_unlock);
+ INTERCEPT_FUNCTION(pthread_rwlock_wrlock);
+
+ INTERCEPT_FUNCTION(sleep);
+ INTERCEPT_FUNCTION(usleep);
+ INTERCEPT_FUNCTION(nanosleep);
+
+ INTERCEPT_FUNCTION(socket);
+ INTERCEPT_FUNCTION(send);
+ INTERCEPT_FUNCTION(sendmsg);
+ INTERCEPT_FUNCTION(sendto);
+ INTERCEPT_FUNCTION(recv);
+ INTERCEPT_FUNCTION(recvmsg);
+ INTERCEPT_FUNCTION(recvfrom);
+ INTERCEPT_FUNCTION(shutdown);
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors.h b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors.h
new file mode 100644
index 000000000000..a3dac27544c6
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors.h
@@ -0,0 +1,15 @@
+//===--- rtsan_interceptors.h - Realtime Sanitizer --------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+namespace __rtsan {
+void InitializeInterceptors();
+} // namespace __rtsan
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_preinit.cpp b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_preinit.cpp
new file mode 100644
index 000000000000..1307268951fb
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_preinit.cpp
@@ -0,0 +1,21 @@
+//===--- rtsan_preinit.cpp - Realtime Sanitizer -----------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include <rtsan/rtsan.h>
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+
+// This section is linked into the main executable when -fsanitize=realtime is
+// specified to perform initialization at a very early stage.
+__attribute__((section(".preinit_array"), used)) static auto preinit =
+ __rtsan_init;
+
+#endif
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_stack.cpp b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_stack.cpp
new file mode 100644
index 000000000000..43fd5fbf0550
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_stack.cpp
@@ -0,0 +1,50 @@
+//===--- rtsan_stack.cpp - Realtime Sanitizer -------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "rtsan_stack.h"
+
+#include <sanitizer_common/sanitizer_flags.h>
+#include <sanitizer_common/sanitizer_stacktrace.h>
+
+using namespace __sanitizer;
+using namespace __rtsan;
+
+// We must define our own implementation of this method for our runtime.
+// This one is just copied from UBSan.
+namespace __sanitizer {
+void BufferedStackTrace::UnwindImpl(uptr pc, uptr bp, void *context,
+ bool request_fast, u32 max_depth) {
+ uptr top = 0;
+ uptr bottom = 0;
+ GetThreadStackTopAndBottom(false, &top, &bottom);
+ bool fast = StackTrace::WillUseFastUnwind(request_fast);
+ Unwind(max_depth, pc, bp, context, top, bottom, fast);
+}
+} // namespace __sanitizer
+
+static void SetGlobalStackTraceFormat() {
+ SetCommonFlagsDefaults();
+ CommonFlags cf;
+ cf.CopyFrom(*common_flags());
+ cf.stack_trace_format = "DEFAULT";
+ cf.external_symbolizer_path = GetEnv("RTSAN_SYMBOLIZER_PATH");
+ OverrideCommonFlags(cf);
+}
+
+void __rtsan::PrintStackTrace() {
+
+ BufferedStackTrace stack{};
+
+ GET_CURRENT_PC_BP;
+ stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal);
+
+ SetGlobalStackTraceFormat();
+ stack.Print();
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_stack.h b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_stack.h
new file mode 100644
index 000000000000..cecdd43045db
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/rtsan_stack.h
@@ -0,0 +1,15 @@
+//===--- rtsan_stack.h - Realtime Sanitizer ---------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+namespace __rtsan {
+void PrintStackTrace();
+} // namespace __rtsan
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_context.cpp b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_context.cpp
new file mode 100644
index 000000000000..b7e73236a14c
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_context.cpp
@@ -0,0 +1,69 @@
+//===--- rtsan_test_context.cpp - Realtime Sanitizer ------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "rtsan_test_utilities.h"
+
+#include "rtsan_context.h"
+
+TEST(TestRtsanContext, CanCreateContext) { __rtsan::Context context{}; }
+
+TEST(TestRtsanContext, ExpectNotRealtimeDoesNotDieBeforeRealtimePush) {
+ __rtsan::Context context{};
+ context.ExpectNotRealtime("do_some_stuff");
+}
+
+TEST(TestRtsanContext, ExpectNotRealtimeDoesNotDieAfterPushAndPop) {
+ __rtsan::Context context{};
+ context.RealtimePush();
+ context.RealtimePop();
+ context.ExpectNotRealtime("do_some_stuff");
+}
+
+TEST(TestRtsanContext, ExpectNotRealtimeDiesAfterRealtimePush) {
+ __rtsan::Context context{};
+
+ context.RealtimePush();
+ EXPECT_DEATH(context.ExpectNotRealtime("do_some_stuff"), "");
+}
+
+TEST(TestRtsanContext,
+ ExpectNotRealtimeDiesAfterRealtimeAfterMorePushesThanPops) {
+ __rtsan::Context context{};
+
+ context.RealtimePush();
+ context.RealtimePush();
+ context.RealtimePush();
+ context.RealtimePop();
+ context.RealtimePop();
+ EXPECT_DEATH(context.ExpectNotRealtime("do_some_stuff"), "");
+}
+
+TEST(TestRtsanContext, ExpectNotRealtimeDoesNotDieAfterBypassPush) {
+ __rtsan::Context context{};
+
+ context.RealtimePush();
+ context.BypassPush();
+ context.ExpectNotRealtime("do_some_stuff");
+}
+
+TEST(TestRtsanContext,
+ ExpectNotRealtimeDoesNotDieIfBypassDepthIsGreaterThanZero) {
+ __rtsan::Context context{};
+
+ context.RealtimePush();
+ context.BypassPush();
+ context.BypassPush();
+ context.BypassPush();
+ context.BypassPop();
+ context.BypassPop();
+ context.ExpectNotRealtime("do_some_stuff");
+ context.BypassPop();
+ EXPECT_DEATH(context.ExpectNotRealtime("do_some_stuff"), "");
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_functional.cpp b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_functional.cpp
new file mode 100644
index 000000000000..97afb1eefb64
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_functional.cpp
@@ -0,0 +1,207 @@
+//===--- rtsan_test.cpp - Realtime Sanitizer --------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Introduces basic functional tests for the realtime sanitizer.
+// Not meant to be exhaustive, testing all interceptors, please see
+// test_rtsan_interceptors.cpp for those tests.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "rtsan_test_utilities.h"
+#include <rtsan.h>
+#include <sanitizer_common/sanitizer_platform.h>
+#include <sanitizer_common/sanitizer_platform_interceptors.h>
+
+#include <array>
+#include <atomic>
+#include <chrono>
+#include <fstream>
+#include <mutex>
+#include <shared_mutex>
+#include <thread>
+
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200
+#define SI_MAC_DEPLOYMENT_AT_LEAST_10_12 1
+#else
+#define SI_MAC_DEPLOYMENT_AT_LEAST_10_12 0
+#endif
+
+#define RTSAN_TEST_SHARED_MUTEX (!(SI_MAC) || SI_MAC_DEPLOYMENT_AT_LEAST_10_12)
+
+using namespace testing;
+using namespace rtsan_testing;
+using namespace std::chrono_literals;
+
+TEST(TestRtsan, VectorPushBackAllocationDiesWhenRealtime) {
+ std::vector<float> vec;
+ auto Func = [&vec]() { vec.push_back(0.4f); };
+ ExpectRealtimeDeath(Func);
+ ASSERT_EQ(0u, vec.size());
+ ExpectNonRealtimeSurvival(Func);
+ ASSERT_EQ(1u, vec.size());
+}
+
+TEST(TestRtsan, DestructionOfObjectOnHeapDiesWhenRealtime) {
+ auto allocated_ptr = std::make_unique<std::array<float, 256>>();
+ auto Func = [&allocated_ptr]() { allocated_ptr.reset(); };
+ ExpectRealtimeDeath(Func);
+ ASSERT_NE(nullptr, allocated_ptr.get());
+ ExpectNonRealtimeSurvival(Func);
+ ASSERT_EQ(nullptr, allocated_ptr.get());
+}
+
+TEST(TestRtsan, SleepingAThreadDiesWhenRealtime) {
+ auto Func = []() { std::this_thread::sleep_for(1us); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, IfstreamCreationDiesWhenRealtime) {
+ auto Func = []() { std::ifstream ifs{"./file.txt"}; };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+ std::remove("./file.txt");
+}
+
+TEST(TestRtsan, OfstreamCreationDiesWhenRealtime) {
+ auto Func = []() { std::ofstream ofs{"./file.txt"}; };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+ std::remove("./file.txt");
+}
+
+TEST(TestRtsan, LockingAMutexDiesWhenRealtime) {
+ std::mutex mutex;
+ auto Func = [&]() { mutex.lock(); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, UnlockingAMutexDiesWhenRealtime) {
+ std::mutex mutex;
+ mutex.lock();
+ auto Func = [&]() { mutex.unlock(); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+#if RTSAN_TEST_SHARED_MUTEX
+
+TEST(TestRtsan, LockingASharedMutexDiesWhenRealtime) {
+ std::shared_mutex mutex;
+ auto Func = [&]() { mutex.lock(); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, UnlockingASharedMutexDiesWhenRealtime) {
+ std::shared_mutex mutex;
+ mutex.lock();
+ auto Func = [&]() { mutex.unlock(); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, SharedLockingASharedMutexDiesWhenRealtime) {
+ std::shared_mutex mutex;
+ auto Func = [&]() { mutex.lock_shared(); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, SharedUnlockingASharedMutexDiesWhenRealtime) {
+ std::shared_mutex mutex;
+ mutex.lock_shared();
+ auto Func = [&]() { mutex.unlock_shared(); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+#endif // RTSAN_TEST_SHARED_MUTEX
+
+TEST(TestRtsan, LaunchingAThreadDiesWhenRealtime) {
+ auto Func = [&]() {
+ std::thread Thread{[]() {}};
+ Thread.join();
+ };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+namespace {
+void InvokeStdFunction(std::function<void()> &&function) { function(); }
+} // namespace
+
+TEST(TestRtsan, CopyingALambdaWithLargeCaptureDiesWhenRealtime) {
+ std::array<float, 16> lots_of_data;
+ auto lambda = [lots_of_data]() mutable {
+ // Stop everything getting optimised out
+ lots_of_data[3] = 0.25f;
+ EXPECT_EQ(16, lots_of_data.size());
+ EXPECT_EQ(0.25f, lots_of_data[3]);
+ };
+ auto Func = [&]() { InvokeStdFunction(lambda); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, AccessingALargeAtomicVariableDiesWhenRealtime) {
+ std::atomic<float> small_atomic{0.0f};
+ ASSERT_TRUE(small_atomic.is_lock_free());
+ RealtimeInvoke([&small_atomic]() { float x = small_atomic.load(); });
+
+ std::atomic<std::array<float, 2048>> large_atomic;
+ ASSERT_FALSE(large_atomic.is_lock_free());
+ auto Func = [&]() { auto x = large_atomic.load(); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, FirstCoutDiesWhenRealtime) {
+ auto Func = []() { std::cout << "Hello, world!" << std::endl; };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, SecondCoutDiesWhenRealtime) {
+ std::cout << "Hello, world";
+ auto Func = []() { std::cout << "Hello, again!" << std::endl; };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, PrintfDiesWhenRealtime) {
+ auto Func = []() { printf("Hello, world!\n"); };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, ThrowingAnExceptionDiesWhenRealtime) {
+ auto Func = [&]() {
+ try {
+ throw std::exception();
+ } catch (std::exception &) {
+ }
+ };
+ ExpectRealtimeDeath(Func);
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsan, DoesNotDieIfTurnedOff) {
+ std::mutex mutex;
+ auto RealtimeUnsafeFunc = [&]() {
+ __rtsan_off();
+ mutex.lock();
+ mutex.unlock();
+ __rtsan_on();
+ };
+ RealtimeInvoke(RealtimeUnsafeFunc);
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp
new file mode 100644
index 000000000000..f5b016089087
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp
@@ -0,0 +1,516 @@
+//===--- rtsan_test_interceptors.cpp - Realtime Sanitizer -------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include <sanitizer_common/sanitizer_platform.h>
+#include <sanitizer_common/sanitizer_platform_interceptors.h>
+
+#include "rtsan_test_utilities.h"
+
+#if SANITIZER_APPLE
+#include <libkern/OSAtomic.h>
+#include <os/lock.h>
+#endif
+
+#if SANITIZER_INTERCEPT_MEMALIGN || SANITIZER_INTERCEPT_PVALLOC
+#include <malloc.h>
+#endif
+
+#include <atomic>
+#include <chrono>
+#include <string>
+#include <thread>
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/socket.h>
+
+using namespace testing;
+using namespace rtsan_testing;
+using namespace std::chrono_literals;
+
+void *FakeThreadEntryPoint(void *) { return nullptr; }
+
+class RtsanFileTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ const ::testing::TestInfo *const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ file_path_ = std::string("/tmp/rtsan_temporary_test_file_") +
+ test_info->name() + ".txt";
+ RemoveTemporaryFile();
+ }
+
+ // Gets a file path with the test's name in it
+ // This file will be removed if it exists at the end of the test
+ const char *GetTemporaryFilePath() const { return file_path_.c_str(); }
+
+ void TearDown() override { RemoveTemporaryFile(); }
+
+private:
+ void RemoveTemporaryFile() const { std::remove(GetTemporaryFilePath()); }
+ std::string file_path_;
+};
+
+/*
+ Allocation and deallocation
+*/
+
+TEST(TestRtsanInterceptors, MallocDiesWhenRealtime) {
+ auto Func = []() { EXPECT_NE(nullptr, malloc(1)); };
+ ExpectRealtimeDeath(Func, "malloc");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, ReallocDiesWhenRealtime) {
+ void *ptr_1 = malloc(1);
+ auto Func = [ptr_1]() { EXPECT_NE(nullptr, realloc(ptr_1, 8)); };
+ ExpectRealtimeDeath(Func, "realloc");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+#if SANITIZER_APPLE
+TEST(TestRtsanInterceptors, ReallocfDiesWhenRealtime) {
+ void *ptr_1 = malloc(1);
+ auto Func = [ptr_1]() { EXPECT_NE(nullptr, reallocf(ptr_1, 8)); };
+ ExpectRealtimeDeath(Func, "reallocf");
+ ExpectNonRealtimeSurvival(Func);
+}
+#endif
+
+TEST(TestRtsanInterceptors, VallocDiesWhenRealtime) {
+ auto Func = []() { EXPECT_NE(nullptr, valloc(4)); };
+ ExpectRealtimeDeath(Func, "valloc");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+#if SANITIZER_INTERCEPT_ALIGNED_ALLOC
+TEST(TestRtsanInterceptors, AlignedAllocDiesWhenRealtime) {
+ auto Func = []() { EXPECT_NE(nullptr, aligned_alloc(16, 32)); };
+ ExpectRealtimeDeath(Func, "aligned_alloc");
+ ExpectNonRealtimeSurvival(Func);
+}
+#endif
+
+// free_sized and free_aligned_sized (both C23) are not yet supported
+TEST(TestRtsanInterceptors, FreeDiesWhenRealtime) {
+ void *ptr_1 = malloc(1);
+ void *ptr_2 = malloc(1);
+ ExpectRealtimeDeath([ptr_1]() { free(ptr_1); }, "free");
+ ExpectNonRealtimeSurvival([ptr_2]() { free(ptr_2); });
+
+ // Prevent malloc/free pair being optimised out
+ ASSERT_NE(nullptr, ptr_1);
+ ASSERT_NE(nullptr, ptr_2);
+}
+
+TEST(TestRtsanInterceptors, FreeSurvivesWhenRealtimeIfArgumentIsNull) {
+ RealtimeInvoke([]() { free(NULL); });
+ ExpectNonRealtimeSurvival([]() { free(NULL); });
+}
+
+TEST(TestRtsanInterceptors, PosixMemalignDiesWhenRealtime) {
+ auto Func = []() {
+ void *ptr;
+ posix_memalign(&ptr, 4, 4);
+ };
+ ExpectRealtimeDeath(Func, "posix_memalign");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+#if SANITIZER_INTERCEPT_MEMALIGN
+TEST(TestRtsanInterceptors, MemalignDiesWhenRealtime) {
+ auto Func = []() { EXPECT_NE(memalign(2, 2048), nullptr); };
+ ExpectRealtimeDeath(Func, "memalign");
+ ExpectNonRealtimeSurvival(Func);
+}
+#endif
+
+#if SANITIZER_INTERCEPT_PVALLOC
+TEST(TestRtsanInterceptors, PvallocDiesWhenRealtime) {
+ auto Func = []() { EXPECT_NE(pvalloc(2048), nullptr); };
+ ExpectRealtimeDeath(Func, "pvalloc");
+ ExpectNonRealtimeSurvival(Func);
+}
+#endif
+
+/*
+ Sleeping
+*/
+
+TEST(TestRtsanInterceptors, SleepDiesWhenRealtime) {
+ auto Func = []() { sleep(0u); };
+ ExpectRealtimeDeath(Func, "sleep");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, UsleepDiesWhenRealtime) {
+ auto Func = []() { usleep(1u); };
+ ExpectRealtimeDeath(Func, "usleep");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, NanosleepDiesWhenRealtime) {
+ auto Func = []() {
+ timespec T{};
+ nanosleep(&T, &T);
+ };
+ ExpectRealtimeDeath(Func, "nanosleep");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+/*
+ Filesystem
+*/
+
+TEST_F(RtsanFileTest, OpenDiesWhenRealtime) {
+ auto func = [this]() { open(GetTemporaryFilePath(), O_RDONLY); };
+ ExpectRealtimeDeath(func, "open");
+ ExpectNonRealtimeSurvival(func);
+}
+
+TEST_F(RtsanFileTest, OpenatDiesWhenRealtime) {
+ auto func = [this]() { openat(0, GetTemporaryFilePath(), O_RDONLY); };
+ ExpectRealtimeDeath(func, "openat");
+ ExpectNonRealtimeSurvival(func);
+}
+
+TEST_F(RtsanFileTest, OpenCreatesFileWithProperMode) {
+ const int mode = S_IRGRP | S_IROTH | S_IRUSR | S_IWUSR;
+
+ const int fd = open(GetTemporaryFilePath(), O_CREAT | O_WRONLY, mode);
+ ASSERT_THAT(fd, Ne(-1));
+ close(fd);
+
+ struct stat st;
+ ASSERT_THAT(stat(GetTemporaryFilePath(), &st), Eq(0));
+
+ // Mask st_mode to get permission bits only
+ ASSERT_THAT(st.st_mode & 0777, Eq(mode));
+}
+
+TEST_F(RtsanFileTest, CreatDiesWhenRealtime) {
+ auto func = [this]() { creat(GetTemporaryFilePath(), S_IWOTH | S_IROTH); };
+ ExpectRealtimeDeath(func, "creat");
+ ExpectNonRealtimeSurvival(func);
+}
+
+TEST(TestRtsanInterceptors, FcntlDiesWhenRealtime) {
+ auto func = []() { fcntl(0, F_GETFL); };
+ ExpectRealtimeDeath(func, "fcntl");
+ ExpectNonRealtimeSurvival(func);
+}
+
+TEST_F(RtsanFileTest, FcntlFlockDiesWhenRealtime) {
+ int fd = creat(GetTemporaryFilePath(), S_IRUSR | S_IWUSR);
+ ASSERT_THAT(fd, Ne(-1));
+
+ auto func = [fd]() {
+ struct flock lock {};
+ lock.l_type = F_RDLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_pid = ::getpid();
+
+ ASSERT_THAT(fcntl(fd, F_GETLK, &lock), Eq(0));
+ ASSERT_THAT(lock.l_type, F_UNLCK);
+ };
+ ExpectRealtimeDeath(func, "fcntl");
+ ExpectNonRealtimeSurvival(func);
+
+ close(fd);
+}
+
+TEST_F(RtsanFileTest, FcntlSetFdDiesWhenRealtime) {
+ int fd = creat(GetTemporaryFilePath(), S_IRUSR | S_IWUSR);
+ ASSERT_THAT(fd, Ne(-1));
+
+ auto func = [fd]() {
+ int old_flags = fcntl(fd, F_GETFD);
+ ASSERT_THAT(fcntl(fd, F_SETFD, FD_CLOEXEC), Eq(0));
+
+ int flags = fcntl(fd, F_GETFD);
+ ASSERT_THAT(flags, Ne(-1));
+ ASSERT_THAT(flags & FD_CLOEXEC, Eq(FD_CLOEXEC));
+
+ ASSERT_THAT(fcntl(fd, F_SETFD, old_flags), Eq(0));
+ ASSERT_THAT(fcntl(fd, F_GETFD), Eq(old_flags));
+ };
+
+ ExpectRealtimeDeath(func, "fcntl");
+ ExpectNonRealtimeSurvival(func);
+
+ close(fd);
+}
+
+TEST(TestRtsanInterceptors, CloseDiesWhenRealtime) {
+ auto func = []() { close(0); };
+ ExpectRealtimeDeath(func, "close");
+ ExpectNonRealtimeSurvival(func);
+}
+
+TEST_F(RtsanFileTest, FopenDiesWhenRealtime) {
+ auto func = [this]() {
+ auto fd = fopen(GetTemporaryFilePath(), "w");
+ EXPECT_THAT(fd, Ne(nullptr));
+ };
+ ExpectRealtimeDeath(func, "fopen");
+ ExpectNonRealtimeSurvival(func);
+}
+
+TEST_F(RtsanFileTest, FreadDiesWhenRealtime) {
+ auto fd = fopen(GetTemporaryFilePath(), "w");
+ auto func = [fd]() {
+ char c{};
+ fread(&c, 1, 1, fd);
+ };
+ ExpectRealtimeDeath(func, "fread");
+ ExpectNonRealtimeSurvival(func);
+ if (fd != nullptr)
+ fclose(fd);
+}
+
+TEST_F(RtsanFileTest, FwriteDiesWhenRealtime) {
+ auto fd = fopen(GetTemporaryFilePath(), "w");
+ ASSERT_NE(nullptr, fd);
+ auto message = "Hello, world!";
+ auto func = [&]() { fwrite(&message, 1, 4, fd); };
+ ExpectRealtimeDeath(func, "fwrite");
+ ExpectNonRealtimeSurvival(func);
+}
+
+TEST_F(RtsanFileTest, FcloseDiesWhenRealtime) {
+ auto fd = fopen(GetTemporaryFilePath(), "w");
+ EXPECT_THAT(fd, Ne(nullptr));
+ auto func = [fd]() { fclose(fd); };
+ ExpectRealtimeDeath(func, "fclose");
+ ExpectNonRealtimeSurvival(func);
+}
+
+TEST(TestRtsanInterceptors, PutsDiesWhenRealtime) {
+ auto func = []() { puts("Hello, world!\n"); };
+ ExpectRealtimeDeath(func);
+ ExpectNonRealtimeSurvival(func);
+}
+
+TEST_F(RtsanFileTest, FputsDiesWhenRealtime) {
+ auto fd = fopen(GetTemporaryFilePath(), "w");
+ ASSERT_THAT(fd, Ne(nullptr)) << errno;
+ auto func = [fd]() { fputs("Hello, world!\n", fd); };
+ ExpectRealtimeDeath(func);
+ ExpectNonRealtimeSurvival(func);
+ if (fd != nullptr)
+ fclose(fd);
+}
+
+/*
+ Concurrency
+*/
+
+TEST(TestRtsanInterceptors, PthreadCreateDiesWhenRealtime) {
+ auto Func = []() {
+ pthread_t thread{};
+ const pthread_attr_t attr{};
+ struct thread_info *thread_info;
+ pthread_create(&thread, &attr, &FakeThreadEntryPoint, thread_info);
+ };
+ ExpectRealtimeDeath(Func, "pthread_create");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, PthreadMutexLockDiesWhenRealtime) {
+ auto Func = []() {
+ pthread_mutex_t mutex{};
+ pthread_mutex_lock(&mutex);
+ };
+
+ ExpectRealtimeDeath(Func, "pthread_mutex_lock");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, PthreadMutexUnlockDiesWhenRealtime) {
+ auto Func = []() {
+ pthread_mutex_t mutex{};
+ pthread_mutex_unlock(&mutex);
+ };
+
+ ExpectRealtimeDeath(Func, "pthread_mutex_unlock");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, PthreadMutexJoinDiesWhenRealtime) {
+ auto Func = []() {
+ pthread_t thread{};
+ pthread_join(thread, nullptr);
+ };
+
+ ExpectRealtimeDeath(Func, "pthread_join");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+#if SANITIZER_APPLE
+
+#pragma clang diagnostic push
+// OSSpinLockLock is deprecated, but still in use in libc++
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+TEST(TestRtsanInterceptors, OsSpinLockLockDiesWhenRealtime) {
+ auto Func = []() {
+ OSSpinLock spin_lock{};
+ OSSpinLockLock(&spin_lock);
+ };
+ ExpectRealtimeDeath(Func, "OSSpinLockLock");
+ ExpectNonRealtimeSurvival(Func);
+}
+#pragma clang diagnostic pop
+
+TEST(TestRtsanInterceptors, OsUnfairLockLockDiesWhenRealtime) {
+ auto Func = []() {
+ os_unfair_lock_s unfair_lock{};
+ os_unfair_lock_lock(&unfair_lock);
+ };
+ ExpectRealtimeDeath(Func, "os_unfair_lock_lock");
+ ExpectNonRealtimeSurvival(Func);
+}
+#endif
+
+#if SANITIZER_LINUX
+TEST(TestRtsanInterceptors, SpinLockLockDiesWhenRealtime) {
+ pthread_spinlock_t spin_lock;
+ pthread_spin_init(&spin_lock, PTHREAD_PROCESS_SHARED);
+ auto Func = [&]() { pthread_spin_lock(&spin_lock); };
+ ExpectRealtimeDeath(Func, "pthread_spin_lock");
+ ExpectNonRealtimeSurvival(Func);
+}
+#endif
+
+TEST(TestRtsanInterceptors, PthreadCondSignalDiesWhenRealtime) {
+ pthread_cond_t cond{};
+ pthread_cond_init(&cond, NULL);
+
+ auto Func = [&cond]() { pthread_cond_signal(&cond); };
+ ExpectRealtimeDeath(Func, "pthread_cond_signal");
+ ExpectNonRealtimeSurvival(Func);
+
+ pthread_cond_destroy(&cond);
+}
+
+TEST(TestRtsanInterceptors, PthreadCondBroadcastDiesWhenRealtime) {
+ pthread_cond_t cond{};
+ pthread_cond_init(&cond, NULL);
+
+ auto Func = [&cond]() { pthread_cond_broadcast(&cond); };
+ ExpectRealtimeDeath(Func, "pthread_cond_broadcast");
+ ExpectNonRealtimeSurvival(Func);
+
+ pthread_cond_destroy(&cond);
+}
+
+TEST(TestRtsanInterceptors, PthreadCondWaitDiesWhenRealtime) {
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+ ASSERT_EQ(0, pthread_cond_init(&cond, nullptr));
+ ASSERT_EQ(0, pthread_mutex_init(&mutex, nullptr));
+
+ auto Func = [&]() { pthread_cond_wait(&cond, &mutex); };
+ ExpectRealtimeDeath(Func, "pthread_cond_wait");
+ // It's very difficult to test the success case here without doing some
+ // sleeping, which is at the mercy of the scheduler. What's really important
+ // here is the interception - so we're only testing that for now.
+
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&mutex);
+}
+
+TEST(TestRtsanInterceptors, PthreadRwlockRdlockDiesWhenRealtime) {
+ auto Func = []() {
+ pthread_rwlock_t rw_lock;
+ pthread_rwlock_rdlock(&rw_lock);
+ };
+ ExpectRealtimeDeath(Func, "pthread_rwlock_rdlock");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, PthreadRwlockUnlockDiesWhenRealtime) {
+ auto Func = []() {
+ pthread_rwlock_t rw_lock;
+ pthread_rwlock_unlock(&rw_lock);
+ };
+ ExpectRealtimeDeath(Func, "pthread_rwlock_unlock");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, PthreadRwlockWrlockDiesWhenRealtime) {
+ auto Func = []() {
+ pthread_rwlock_t rw_lock;
+ pthread_rwlock_wrlock(&rw_lock);
+ };
+ ExpectRealtimeDeath(Func, "pthread_rwlock_wrlock");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+/*
+ Sockets
+*/
+TEST(TestRtsanInterceptors, OpeningASocketDiesWhenRealtime) {
+ auto Func = []() { socket(PF_INET, SOCK_STREAM, 0); };
+ ExpectRealtimeDeath(Func, "socket");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, SendToASocketDiesWhenRealtime) {
+ auto Func = []() { send(0, nullptr, 0, 0); };
+ ExpectRealtimeDeath(Func, "send");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, SendmsgToASocketDiesWhenRealtime) {
+ msghdr msg{};
+ auto Func = [&]() { sendmsg(0, &msg, 0); };
+ ExpectRealtimeDeath(Func, "sendmsg");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, SendtoToASocketDiesWhenRealtime) {
+ sockaddr addr{};
+ socklen_t len{};
+ auto Func = [&]() { sendto(0, nullptr, 0, 0, &addr, len); };
+ ExpectRealtimeDeath(Func, "sendto");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, RecvFromASocketDiesWhenRealtime) {
+ auto Func = []() { recv(0, nullptr, 0, 0); };
+ ExpectRealtimeDeath(Func, "recv");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, RecvfromOnASocketDiesWhenRealtime) {
+ sockaddr addr{};
+ socklen_t len{};
+ auto Func = [&]() { recvfrom(0, nullptr, 0, 0, &addr, &len); };
+ ExpectRealtimeDeath(Func, "recvfrom");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, RecvmsgOnASocketDiesWhenRealtime) {
+ msghdr msg{};
+ auto Func = [&]() { recvmsg(0, &msg, 0); };
+ ExpectRealtimeDeath(Func, "recvmsg");
+ ExpectNonRealtimeSurvival(Func);
+}
+
+TEST(TestRtsanInterceptors, ShutdownOnASocketDiesWhenRealtime) {
+ auto Func = [&]() { shutdown(0, 0); };
+ ExpectRealtimeDeath(Func, "shutdown");
+ ExpectNonRealtimeSurvival(Func);
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_main.cpp b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_main.cpp
new file mode 100644
index 000000000000..255ac9497103
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_main.cpp
@@ -0,0 +1,17 @@
+//===--- rtsan_test_main.cpp - Realtime Sanitizer ---------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_test_utils.h"
+
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_utilities.h b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_utilities.h
new file mode 100644
index 000000000000..6ca09cf65709
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_utilities.h
@@ -0,0 +1,47 @@
+//===--- rtsan_test_utilities.h - Realtime Sanitizer ------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include "rtsan.h"
+#include "gmock/gmock.h"
+#include <string>
+
+namespace rtsan_testing {
+
+template <typename Function> void RealtimeInvoke(Function &&Func) {
+ __rtsan_realtime_enter();
+ std::forward<Function>(Func)();
+ __rtsan_realtime_exit();
+}
+
+template <typename Function>
+void ExpectRealtimeDeath(Function &&Func,
+ const char *intercepted_method_name = nullptr) {
+
+ using namespace testing;
+
+ auto GetExpectedErrorSubstring = [&]() -> std::string {
+ return intercepted_method_name != nullptr
+ ? "Real-time violation: intercepted call to real-time unsafe "
+ "function `" +
+ std::string(intercepted_method_name) + "`"
+ : "";
+ };
+
+ EXPECT_EXIT(RealtimeInvoke(std::forward<Function>(Func)),
+ ExitedWithCode(EXIT_FAILURE), GetExpectedErrorSubstring());
+}
+
+template <typename Function> void ExpectNonRealtimeSurvival(Function &&Func) {
+ std::forward<Function>(Func)();
+}
+
+} // namespace rtsan_testing