brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · e05d7ae Raw
231 lines · cpp
1//===--- rtsan_test.cpp - Realtime Sanitizer --------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Introduces basic functional tests for the realtime sanitizer.10// Not meant to be exhaustive, testing all interceptors, please see11// test_rtsan_interceptors.cpp for those tests.12//13//===----------------------------------------------------------------------===//14 15#include "gtest/gtest.h"16 17#include "rtsan_test_utilities.h"18 19#include "rtsan/rtsan.h"20#include "sanitizer_common/sanitizer_platform.h"21#include "sanitizer_common/sanitizer_platform_interceptors.h"22 23#include <array>24#include <atomic>25#include <chrono>26#include <fstream>27#include <mutex>28#include <shared_mutex>29#include <thread>30 31#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) &&                  \32    __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 10120033#define SI_MAC_DEPLOYMENT_AT_LEAST_10_12 134#else35#define SI_MAC_DEPLOYMENT_AT_LEAST_10_12 036#endif37 38#define RTSAN_TEST_SHARED_MUTEX (!(SI_MAC) || SI_MAC_DEPLOYMENT_AT_LEAST_10_12)39 40using namespace testing;41using namespace rtsan_testing;42using namespace std::chrono_literals;43 44TEST(TestRtsan, VectorPushBackAllocationDiesWhenRealtime) {45  std::vector<float> vec;46  auto Func = [&vec]() { vec.push_back(0.4f); };47  ExpectRealtimeDeath(Func);48  ASSERT_EQ(0u, vec.size());49  ExpectNonRealtimeSurvival(Func);50  ASSERT_EQ(1u, vec.size());51}52 53TEST(TestRtsan, DestructionOfObjectOnHeapDiesWhenRealtime) {54  auto allocated_ptr = std::make_unique<std::array<float, 256>>();55  auto Func = [&allocated_ptr]() { allocated_ptr.reset(); };56  ExpectRealtimeDeath(Func);57  ASSERT_NE(nullptr, allocated_ptr.get());58  ExpectNonRealtimeSurvival(Func);59  ASSERT_EQ(nullptr, allocated_ptr.get());60}61 62TEST(TestRtsan, SleepingAThreadDiesWhenRealtime) {63  auto Func = []() { std::this_thread::sleep_for(1us); };64  ExpectRealtimeDeath(Func);65  ExpectNonRealtimeSurvival(Func);66}67 68TEST(TestRtsan, YieldingDiesWhenRealtime) {69  auto Func = []() { std::this_thread::yield(); };70  ExpectRealtimeDeath(Func);71  ExpectNonRealtimeSurvival(Func);72}73 74TEST(TestRtsan, IfstreamCreationDiesWhenRealtime) {75  auto Func = []() { std::ifstream ifs{"./file.txt"}; };76  ExpectRealtimeDeath(Func);77  ExpectNonRealtimeSurvival(Func);78  std::remove("./file.txt");79}80 81TEST(TestRtsan, OfstreamCreationDiesWhenRealtime) {82  auto Func = []() { std::ofstream ofs{"./file.txt"}; };83  ExpectRealtimeDeath(Func);84  ExpectNonRealtimeSurvival(Func);85  std::remove("./file.txt");86}87 88TEST(TestRtsan, LockingAMutexDiesWhenRealtime) {89  std::mutex mutex;90  auto Func = [&]() { mutex.lock(); };91  ExpectRealtimeDeath(Func);92  ExpectNonRealtimeSurvival(Func);93}94 95TEST(TestRtsan, UnlockingAMutexDiesWhenRealtime) {96  std::mutex mutex;97  mutex.lock();98  auto Func = [&]() { mutex.unlock(); };99  ExpectRealtimeDeath(Func);100  ExpectNonRealtimeSurvival(Func);101}102 103#if RTSAN_TEST_SHARED_MUTEX104 105TEST(TestRtsan, LockingASharedMutexDiesWhenRealtime) {106  std::shared_mutex mutex;107  auto Func = [&]() { mutex.lock(); };108  ExpectRealtimeDeath(Func);109  ExpectNonRealtimeSurvival(Func);110}111 112TEST(TestRtsan, UnlockingASharedMutexDiesWhenRealtime) {113  std::shared_mutex mutex;114  mutex.lock();115  auto Func = [&]() { mutex.unlock(); };116  ExpectRealtimeDeath(Func);117  ExpectNonRealtimeSurvival(Func);118}119 120TEST(TestRtsan, SharedLockingASharedMutexDiesWhenRealtime) {121  std::shared_mutex mutex;122  auto Func = [&]() { mutex.lock_shared(); };123  ExpectRealtimeDeath(Func);124  ExpectNonRealtimeSurvival(Func);125}126 127TEST(TestRtsan, SharedUnlockingASharedMutexDiesWhenRealtime) {128  std::shared_mutex mutex;129  mutex.lock_shared();130  auto Func = [&]() { mutex.unlock_shared(); };131  ExpectRealtimeDeath(Func);132  ExpectNonRealtimeSurvival(Func);133}134 135#endif // RTSAN_TEST_SHARED_MUTEX136 137TEST(TestRtsan, LaunchingAThreadDiesWhenRealtime) {138  auto Func = [&]() {139    std::thread Thread{[]() {}};140    Thread.join();141  };142  ExpectRealtimeDeath(Func);143  ExpectNonRealtimeSurvival(Func);144}145 146namespace {147void InvokeStdFunction(std::function<void()> &&function) { function(); }148 149template <typename T> void HideMemoryFromCompiler(T *memory) {150  // Pass the pointer to an empty assembly block as an input, and inform151  // the compiler that memory is read to and possibly modified. This should not152  // be architecture specific, since the asm block is empty.153  __asm__ __volatile__("" ::"r"(memory) : "memory");154}155} // namespace156 157TEST(TestRtsan, CopyingALambdaWithLargeCaptureDiesWhenRealtime) {158  std::array<float, 16> lots_of_data;159  auto LargeLambda = [lots_of_data]() mutable {160    lots_of_data[3] = 0.25f;161    // In LTO builds, this lambda can be optimized away, since the compiler can162    // see through the memory accesses after inlining across TUs. Ensure it can163    // no longer reason about the memory access, so that won't happen.164    HideMemoryFromCompiler(&lots_of_data[3]);165    EXPECT_EQ(16u, lots_of_data.size());166    EXPECT_EQ(0.25f, lots_of_data[3]);167  };168  auto Func = [&]() { InvokeStdFunction(LargeLambda); };169  ExpectRealtimeDeath(Func);170  ExpectNonRealtimeSurvival(Func);171}172 173TEST(TestRtsan, AccessingALargeAtomicVariableDiesWhenRealtime) {174  std::atomic<float> small_atomic{0.0f};175  ASSERT_TRUE(small_atomic.is_lock_free());176  RealtimeInvoke([&small_atomic]() {177    float x = small_atomic.load();178    return x;179  });180 181  std::atomic<std::array<float, 2048>> large_atomic;182  ASSERT_FALSE(large_atomic.is_lock_free());183  auto Func = [&]() {184    std::array<float, 2048> x = large_atomic.load();185    return x;186  };187  ExpectRealtimeDeath(Func);188  ExpectNonRealtimeSurvival(Func);189}190 191TEST(TestRtsan, FirstCoutDiesWhenRealtime) {192  auto Func = []() { std::cout << "Hello, world!" << std::endl; };193  ExpectRealtimeDeath(Func);194  ExpectNonRealtimeSurvival(Func);195}196 197TEST(TestRtsan, SecondCoutDiesWhenRealtime) {198  std::cout << "Hello, world";199  auto Func = []() { std::cout << "Hello, again!" << std::endl; };200  ExpectRealtimeDeath(Func);201  ExpectNonRealtimeSurvival(Func);202}203 204TEST(TestRtsan, PrintfDiesWhenRealtime) {205  auto Func = []() { printf("Hello, world!\n"); };206  ExpectRealtimeDeath(Func);207  ExpectNonRealtimeSurvival(Func);208}209 210TEST(TestRtsan, ThrowingAnExceptionDiesWhenRealtime) {211  auto Func = [&]() {212    try {213      throw std::exception();214    } catch (std::exception &) {215    }216  };217  ExpectRealtimeDeath(Func);218  ExpectNonRealtimeSurvival(Func);219}220 221TEST(TestRtsan, DoesNotDieIfTurnedOff) {222  std::mutex mutex;223  auto RealtimeBlockingFunc = [&]() {224    __rtsan_disable();225    mutex.lock();226    mutex.unlock();227    __rtsan_enable();228  };229  RealtimeInvoke(RealtimeBlockingFunc);230}231