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