1*0fca6ea1SDimitry Andric //===--- rtsan_test.cpp - Realtime Sanitizer --------------------*- C++ -*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // Introduces basic functional tests for the realtime sanitizer. 10*0fca6ea1SDimitry Andric // Not meant to be exhaustive, testing all interceptors, please see 11*0fca6ea1SDimitry Andric // test_rtsan_interceptors.cpp for those tests. 12*0fca6ea1SDimitry Andric // 13*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 14*0fca6ea1SDimitry Andric 15*0fca6ea1SDimitry Andric #include "gtest/gtest.h" 16*0fca6ea1SDimitry Andric 17*0fca6ea1SDimitry Andric #include "rtsan_test_utilities.h" 18*0fca6ea1SDimitry Andric #include <rtsan.h> 19*0fca6ea1SDimitry Andric #include <sanitizer_common/sanitizer_platform.h> 20*0fca6ea1SDimitry Andric #include <sanitizer_common/sanitizer_platform_interceptors.h> 21*0fca6ea1SDimitry Andric 22*0fca6ea1SDimitry Andric #include <array> 23*0fca6ea1SDimitry Andric #include <atomic> 24*0fca6ea1SDimitry Andric #include <chrono> 25*0fca6ea1SDimitry Andric #include <fstream> 26*0fca6ea1SDimitry Andric #include <mutex> 27*0fca6ea1SDimitry Andric #include <shared_mutex> 28*0fca6ea1SDimitry Andric #include <thread> 29*0fca6ea1SDimitry Andric 30*0fca6ea1SDimitry Andric #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ 31*0fca6ea1SDimitry Andric __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200 32*0fca6ea1SDimitry Andric #define SI_MAC_DEPLOYMENT_AT_LEAST_10_12 1 33*0fca6ea1SDimitry Andric #else 34*0fca6ea1SDimitry Andric #define SI_MAC_DEPLOYMENT_AT_LEAST_10_12 0 35*0fca6ea1SDimitry Andric #endif 36*0fca6ea1SDimitry Andric 37*0fca6ea1SDimitry Andric #define RTSAN_TEST_SHARED_MUTEX (!(SI_MAC) || SI_MAC_DEPLOYMENT_AT_LEAST_10_12) 38*0fca6ea1SDimitry Andric 39*0fca6ea1SDimitry Andric using namespace testing; 40*0fca6ea1SDimitry Andric using namespace rtsan_testing; 41*0fca6ea1SDimitry Andric using namespace std::chrono_literals; 42*0fca6ea1SDimitry Andric 43*0fca6ea1SDimitry Andric TEST(TestRtsan, VectorPushBackAllocationDiesWhenRealtime) { 44*0fca6ea1SDimitry Andric std::vector<float> vec; 45*0fca6ea1SDimitry Andric auto Func = [&vec]() { vec.push_back(0.4f); }; 46*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 47*0fca6ea1SDimitry Andric ASSERT_EQ(0u, vec.size()); 48*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 49*0fca6ea1SDimitry Andric ASSERT_EQ(1u, vec.size()); 50*0fca6ea1SDimitry Andric } 51*0fca6ea1SDimitry Andric 52*0fca6ea1SDimitry Andric TEST(TestRtsan, DestructionOfObjectOnHeapDiesWhenRealtime) { 53*0fca6ea1SDimitry Andric auto allocated_ptr = std::make_unique<std::array<float, 256>>(); 54*0fca6ea1SDimitry Andric auto Func = [&allocated_ptr]() { allocated_ptr.reset(); }; 55*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 56*0fca6ea1SDimitry Andric ASSERT_NE(nullptr, allocated_ptr.get()); 57*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 58*0fca6ea1SDimitry Andric ASSERT_EQ(nullptr, allocated_ptr.get()); 59*0fca6ea1SDimitry Andric } 60*0fca6ea1SDimitry Andric 61*0fca6ea1SDimitry Andric TEST(TestRtsan, SleepingAThreadDiesWhenRealtime) { 62*0fca6ea1SDimitry Andric auto Func = []() { std::this_thread::sleep_for(1us); }; 63*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 64*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 65*0fca6ea1SDimitry Andric } 66*0fca6ea1SDimitry Andric 67*0fca6ea1SDimitry Andric TEST(TestRtsan, IfstreamCreationDiesWhenRealtime) { 68*0fca6ea1SDimitry Andric auto Func = []() { std::ifstream ifs{"./file.txt"}; }; 69*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 70*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 71*0fca6ea1SDimitry Andric std::remove("./file.txt"); 72*0fca6ea1SDimitry Andric } 73*0fca6ea1SDimitry Andric 74*0fca6ea1SDimitry Andric TEST(TestRtsan, OfstreamCreationDiesWhenRealtime) { 75*0fca6ea1SDimitry Andric auto Func = []() { std::ofstream ofs{"./file.txt"}; }; 76*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 77*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 78*0fca6ea1SDimitry Andric std::remove("./file.txt"); 79*0fca6ea1SDimitry Andric } 80*0fca6ea1SDimitry Andric 81*0fca6ea1SDimitry Andric TEST(TestRtsan, LockingAMutexDiesWhenRealtime) { 82*0fca6ea1SDimitry Andric std::mutex mutex; 83*0fca6ea1SDimitry Andric auto Func = [&]() { mutex.lock(); }; 84*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 85*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 86*0fca6ea1SDimitry Andric } 87*0fca6ea1SDimitry Andric 88*0fca6ea1SDimitry Andric TEST(TestRtsan, UnlockingAMutexDiesWhenRealtime) { 89*0fca6ea1SDimitry Andric std::mutex mutex; 90*0fca6ea1SDimitry Andric mutex.lock(); 91*0fca6ea1SDimitry Andric auto Func = [&]() { mutex.unlock(); }; 92*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 93*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 94*0fca6ea1SDimitry Andric } 95*0fca6ea1SDimitry Andric 96*0fca6ea1SDimitry Andric #if RTSAN_TEST_SHARED_MUTEX 97*0fca6ea1SDimitry Andric 98*0fca6ea1SDimitry Andric TEST(TestRtsan, LockingASharedMutexDiesWhenRealtime) { 99*0fca6ea1SDimitry Andric std::shared_mutex mutex; 100*0fca6ea1SDimitry Andric auto Func = [&]() { mutex.lock(); }; 101*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 102*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 103*0fca6ea1SDimitry Andric } 104*0fca6ea1SDimitry Andric 105*0fca6ea1SDimitry Andric TEST(TestRtsan, UnlockingASharedMutexDiesWhenRealtime) { 106*0fca6ea1SDimitry Andric std::shared_mutex mutex; 107*0fca6ea1SDimitry Andric mutex.lock(); 108*0fca6ea1SDimitry Andric auto Func = [&]() { mutex.unlock(); }; 109*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 110*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 111*0fca6ea1SDimitry Andric } 112*0fca6ea1SDimitry Andric 113*0fca6ea1SDimitry Andric TEST(TestRtsan, SharedLockingASharedMutexDiesWhenRealtime) { 114*0fca6ea1SDimitry Andric std::shared_mutex mutex; 115*0fca6ea1SDimitry Andric auto Func = [&]() { mutex.lock_shared(); }; 116*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 117*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 118*0fca6ea1SDimitry Andric } 119*0fca6ea1SDimitry Andric 120*0fca6ea1SDimitry Andric TEST(TestRtsan, SharedUnlockingASharedMutexDiesWhenRealtime) { 121*0fca6ea1SDimitry Andric std::shared_mutex mutex; 122*0fca6ea1SDimitry Andric mutex.lock_shared(); 123*0fca6ea1SDimitry Andric auto Func = [&]() { mutex.unlock_shared(); }; 124*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 125*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 126*0fca6ea1SDimitry Andric } 127*0fca6ea1SDimitry Andric 128*0fca6ea1SDimitry Andric #endif // RTSAN_TEST_SHARED_MUTEX 129*0fca6ea1SDimitry Andric 130*0fca6ea1SDimitry Andric TEST(TestRtsan, LaunchingAThreadDiesWhenRealtime) { 131*0fca6ea1SDimitry Andric auto Func = [&]() { 132*0fca6ea1SDimitry Andric std::thread Thread{[]() {}}; 133*0fca6ea1SDimitry Andric Thread.join(); 134*0fca6ea1SDimitry Andric }; 135*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 136*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 137*0fca6ea1SDimitry Andric } 138*0fca6ea1SDimitry Andric 139*0fca6ea1SDimitry Andric namespace { 140*0fca6ea1SDimitry Andric void InvokeStdFunction(std::function<void()> &&function) { function(); } 141*0fca6ea1SDimitry Andric } // namespace 142*0fca6ea1SDimitry Andric 143*0fca6ea1SDimitry Andric TEST(TestRtsan, CopyingALambdaWithLargeCaptureDiesWhenRealtime) { 144*0fca6ea1SDimitry Andric std::array<float, 16> lots_of_data; 145*0fca6ea1SDimitry Andric auto lambda = [lots_of_data]() mutable { 146*0fca6ea1SDimitry Andric // Stop everything getting optimised out 147*0fca6ea1SDimitry Andric lots_of_data[3] = 0.25f; 148*0fca6ea1SDimitry Andric EXPECT_EQ(16, lots_of_data.size()); 149*0fca6ea1SDimitry Andric EXPECT_EQ(0.25f, lots_of_data[3]); 150*0fca6ea1SDimitry Andric }; 151*0fca6ea1SDimitry Andric auto Func = [&]() { InvokeStdFunction(lambda); }; 152*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 153*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 154*0fca6ea1SDimitry Andric } 155*0fca6ea1SDimitry Andric 156*0fca6ea1SDimitry Andric TEST(TestRtsan, AccessingALargeAtomicVariableDiesWhenRealtime) { 157*0fca6ea1SDimitry Andric std::atomic<float> small_atomic{0.0f}; 158*0fca6ea1SDimitry Andric ASSERT_TRUE(small_atomic.is_lock_free()); 159*0fca6ea1SDimitry Andric RealtimeInvoke([&small_atomic]() { float x = small_atomic.load(); }); 160*0fca6ea1SDimitry Andric 161*0fca6ea1SDimitry Andric std::atomic<std::array<float, 2048>> large_atomic; 162*0fca6ea1SDimitry Andric ASSERT_FALSE(large_atomic.is_lock_free()); 163*0fca6ea1SDimitry Andric auto Func = [&]() { auto x = large_atomic.load(); }; 164*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 165*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 166*0fca6ea1SDimitry Andric } 167*0fca6ea1SDimitry Andric 168*0fca6ea1SDimitry Andric TEST(TestRtsan, FirstCoutDiesWhenRealtime) { 169*0fca6ea1SDimitry Andric auto Func = []() { std::cout << "Hello, world!" << std::endl; }; 170*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 171*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 172*0fca6ea1SDimitry Andric } 173*0fca6ea1SDimitry Andric 174*0fca6ea1SDimitry Andric TEST(TestRtsan, SecondCoutDiesWhenRealtime) { 175*0fca6ea1SDimitry Andric std::cout << "Hello, world"; 176*0fca6ea1SDimitry Andric auto Func = []() { std::cout << "Hello, again!" << std::endl; }; 177*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 178*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 179*0fca6ea1SDimitry Andric } 180*0fca6ea1SDimitry Andric 181*0fca6ea1SDimitry Andric TEST(TestRtsan, PrintfDiesWhenRealtime) { 182*0fca6ea1SDimitry Andric auto Func = []() { printf("Hello, world!\n"); }; 183*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 184*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 185*0fca6ea1SDimitry Andric } 186*0fca6ea1SDimitry Andric 187*0fca6ea1SDimitry Andric TEST(TestRtsan, ThrowingAnExceptionDiesWhenRealtime) { 188*0fca6ea1SDimitry Andric auto Func = [&]() { 189*0fca6ea1SDimitry Andric try { 190*0fca6ea1SDimitry Andric throw std::exception(); 191*0fca6ea1SDimitry Andric } catch (std::exception &) { 192*0fca6ea1SDimitry Andric } 193*0fca6ea1SDimitry Andric }; 194*0fca6ea1SDimitry Andric ExpectRealtimeDeath(Func); 195*0fca6ea1SDimitry Andric ExpectNonRealtimeSurvival(Func); 196*0fca6ea1SDimitry Andric } 197*0fca6ea1SDimitry Andric 198*0fca6ea1SDimitry Andric TEST(TestRtsan, DoesNotDieIfTurnedOff) { 199*0fca6ea1SDimitry Andric std::mutex mutex; 200*0fca6ea1SDimitry Andric auto RealtimeUnsafeFunc = [&]() { 201*0fca6ea1SDimitry Andric __rtsan_off(); 202*0fca6ea1SDimitry Andric mutex.lock(); 203*0fca6ea1SDimitry Andric mutex.unlock(); 204*0fca6ea1SDimitry Andric __rtsan_on(); 205*0fca6ea1SDimitry Andric }; 206*0fca6ea1SDimitry Andric RealtimeInvoke(RealtimeUnsafeFunc); 207*0fca6ea1SDimitry Andric } 208