aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/compiler-rt/lib/rtsan/tests
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/compiler-rt/lib/rtsan/tests')
-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
5 files changed, 856 insertions, 0 deletions
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