diff options
Diffstat (limited to 'contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp')
-rw-r--r-- | contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp | 516 |
1 files changed, 516 insertions, 0 deletions
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); +} |