xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/rtsan/tests/rtsan_test_functional.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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