1 //===-- tsan_trace_test.cpp -----------------------------------------------===//
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 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //
11 //===----------------------------------------------------------------------===//
12 #include "tsan_trace.h"
13 
14 #include <pthread.h>
15 
16 #include "gtest/gtest.h"
17 #include "tsan_rtl.h"
18 
19 #if SANITIZER_MAC || !defined(__x86_64__)
20 // These tests are currently crashing on Mac:
21 // https://reviews.llvm.org/D107911
22 // and on ppc64: https://reviews.llvm.org/D110546#3025422
23 // due to the way we create thread contexts
24 // (but they crashed on Mac with normal pthread_create as well).
25 // There must be some difference in thread initialization
26 // between normal execution and unit tests.
27 #  define TRACE_TEST(SUITE, NAME) TEST(SUITE, DISABLED_##NAME)
28 #else
29 #  define TRACE_TEST(SUITE, NAME) TEST(SUITE, NAME)
30 #endif
31 
32 namespace __tsan {
33 
34 using namespace v3;
35 
36 // We need to run all trace tests in a new thread,
37 // so that the thread trace is empty initially.
38 template <uptr N>
39 struct ThreadArray {
40   ThreadArray() {
41     for (auto *&thr : threads) {
42       thr = static_cast<ThreadState *>(
43           MmapOrDie(sizeof(ThreadState), "ThreadState"));
44       Tid tid = ThreadCreate(cur_thread(), 0, 0, true);
45       Processor *proc = ProcCreate();
46       ProcWire(proc, thr);
47       ThreadStart(thr, tid, 0, ThreadType::Fiber);
48     }
49   }
50 
51   ~ThreadArray() {
52     for (uptr i = 0; i < N; i++) {
53       if (threads[i])
54         Finish(i);
55     }
56   }
57 
58   void Finish(uptr i) {
59     auto *thr = threads[i];
60     threads[i] = nullptr;
61     Processor *proc = thr->proc();
62     ThreadFinish(thr);
63     ProcUnwire(proc, thr);
64     ProcDestroy(proc);
65     UnmapOrDie(thr, sizeof(ThreadState));
66   }
67 
68   ThreadState *threads[N];
69   ThreadState *operator[](uptr i) { return threads[i]; }
70   ThreadState *operator->() { return threads[0]; }
71   operator ThreadState *() { return threads[0]; }
72 };
73 
74 TRACE_TEST(Trace, RestoreAccess) {
75   // A basic test with some function entry/exit events,
76   // some mutex lock/unlock events and some other distracting
77   // memory events.
78   ThreadArray<1> thr;
79   TraceFunc(thr, 0x1000);
80   TraceFunc(thr, 0x1001);
81   TraceMutexLock(thr, v3::EventType::kLock, 0x4000, 0x5000, 0x6000);
82   TraceMutexLock(thr, v3::EventType::kLock, 0x4001, 0x5001, 0x6001);
83   TraceMutexUnlock(thr, 0x5000);
84   TraceFunc(thr);
85   CHECK(TryTraceMemoryAccess(thr, 0x2001, 0x3001, 8, kAccessRead));
86   TraceMutexLock(thr, v3::EventType::kRLock, 0x4002, 0x5002, 0x6002);
87   TraceFunc(thr, 0x1002);
88   CHECK(TryTraceMemoryAccess(thr, 0x2000, 0x3000, 8, kAccessRead));
89   // This is the access we want to find.
90   // The previous one is equivalent, but RestoreStack must prefer
91   // the last of the matchig accesses.
92   CHECK(TryTraceMemoryAccess(thr, 0x2002, 0x3000, 8, kAccessRead));
93   Lock lock1(&ctx->slot_mtx);
94   ThreadRegistryLock lock2(&ctx->thread_registry);
95   VarSizeStackTrace stk;
96   MutexSet mset;
97   uptr tag = kExternalTagNone;
98   bool res =
99       RestoreStack(thr->tid, v3::EventType::kAccessExt, thr->sid, thr->epoch,
100                    0x3000, 8, kAccessRead, &stk, &mset, &tag);
101   CHECK(res);
102   CHECK_EQ(stk.size, 3);
103   CHECK_EQ(stk.trace[0], 0x1000);
104   CHECK_EQ(stk.trace[1], 0x1002);
105   CHECK_EQ(stk.trace[2], 0x2002);
106   CHECK_EQ(mset.Size(), 2);
107   CHECK_EQ(mset.Get(0).addr, 0x5001);
108   CHECK_EQ(mset.Get(0).stack_id, 0x6001);
109   CHECK_EQ(mset.Get(0).write, true);
110   CHECK_EQ(mset.Get(1).addr, 0x5002);
111   CHECK_EQ(mset.Get(1).stack_id, 0x6002);
112   CHECK_EQ(mset.Get(1).write, false);
113   CHECK_EQ(tag, kExternalTagNone);
114 }
115 
116 TRACE_TEST(Trace, MemoryAccessSize) {
117   // Test tracing and matching of accesses of different sizes.
118   struct Params {
119     uptr access_size, offset, size;
120     bool res;
121   };
122   Params tests[] = {
123       {1, 0, 1, true},  {4, 0, 2, true},
124       {4, 2, 2, true},  {8, 3, 1, true},
125       {2, 1, 1, true},  {1, 1, 1, false},
126       {8, 5, 4, false}, {4, static_cast<uptr>(-1l), 4, false},
127   };
128   for (auto params : tests) {
129     for (int type = 0; type < 3; type++) {
130       ThreadArray<1> thr;
131       Printf("access_size=%zu, offset=%zu, size=%zu, res=%d, type=%d\n",
132              params.access_size, params.offset, params.size, params.res, type);
133       TraceFunc(thr, 0x1000);
134       switch (type) {
135         case 0:
136           // This should emit compressed event.
137           CHECK(TryTraceMemoryAccess(thr, 0x2000, 0x3000, params.access_size,
138                                      kAccessRead));
139           break;
140         case 1:
141           // This should emit full event.
142           CHECK(TryTraceMemoryAccess(thr, 0x2000000, 0x3000, params.access_size,
143                                      kAccessRead));
144           break;
145         case 2:
146           TraceMemoryAccessRange(thr, 0x2000000, 0x3000, params.access_size,
147                                  kAccessRead);
148           break;
149       }
150       Lock lock1(&ctx->slot_mtx);
151       ThreadRegistryLock lock2(&ctx->thread_registry);
152       VarSizeStackTrace stk;
153       MutexSet mset;
154       uptr tag = kExternalTagNone;
155       bool res = RestoreStack(thr->tid, v3::EventType::kAccessExt, thr->sid,
156                               thr->epoch, 0x3000 + params.offset, params.size,
157                               kAccessRead, &stk, &mset, &tag);
158       CHECK_EQ(res, params.res);
159       if (params.res) {
160         CHECK_EQ(stk.size, 2);
161         CHECK_EQ(stk.trace[0], 0x1000);
162         CHECK_EQ(stk.trace[1], type ? 0x2000000 : 0x2000);
163       }
164     }
165   }
166 }
167 
168 TRACE_TEST(Trace, RestoreMutexLock) {
169   // Check of restoration of a mutex lock event.
170   ThreadArray<1> thr;
171   TraceFunc(thr, 0x1000);
172   TraceMutexLock(thr, v3::EventType::kLock, 0x4000, 0x5000, 0x6000);
173   TraceMutexLock(thr, v3::EventType::kRLock, 0x4001, 0x5001, 0x6001);
174   TraceMutexLock(thr, v3::EventType::kRLock, 0x4002, 0x5001, 0x6002);
175   Lock lock1(&ctx->slot_mtx);
176   ThreadRegistryLock lock2(&ctx->thread_registry);
177   VarSizeStackTrace stk;
178   MutexSet mset;
179   uptr tag = kExternalTagNone;
180   bool res = RestoreStack(thr->tid, v3::EventType::kLock, thr->sid, thr->epoch,
181                           0x5001, 0, 0, &stk, &mset, &tag);
182   CHECK(res);
183   CHECK_EQ(stk.size, 2);
184   CHECK_EQ(stk.trace[0], 0x1000);
185   CHECK_EQ(stk.trace[1], 0x4002);
186   CHECK_EQ(mset.Size(), 2);
187   CHECK_EQ(mset.Get(0).addr, 0x5000);
188   CHECK_EQ(mset.Get(0).stack_id, 0x6000);
189   CHECK_EQ(mset.Get(0).write, true);
190   CHECK_EQ(mset.Get(1).addr, 0x5001);
191   CHECK_EQ(mset.Get(1).stack_id, 0x6001);
192   CHECK_EQ(mset.Get(1).write, false);
193 }
194 
195 TRACE_TEST(Trace, MultiPart) {
196   // Check replay of a trace with multiple parts.
197   ThreadArray<1> thr;
198   TraceFunc(thr, 0x1000);
199   TraceFunc(thr, 0x2000);
200   TraceMutexLock(thr, v3::EventType::kLock, 0x4000, 0x5000, 0x6000);
201   const uptr kEvents = 3 * sizeof(TracePart) / sizeof(v3::Event);
202   for (uptr i = 0; i < kEvents; i++) {
203     TraceFunc(thr, 0x3000);
204     TraceMutexLock(thr, v3::EventType::kLock, 0x4002, 0x5002, 0x6002);
205     TraceMutexUnlock(thr, 0x5002);
206     TraceFunc(thr);
207   }
208   TraceFunc(thr, 0x4000);
209   TraceMutexLock(thr, v3::EventType::kRLock, 0x4001, 0x5001, 0x6001);
210   CHECK(TryTraceMemoryAccess(thr, 0x2002, 0x3000, 8, kAccessRead));
211   Lock lock1(&ctx->slot_mtx);
212   ThreadRegistryLock lock2(&ctx->thread_registry);
213   VarSizeStackTrace stk;
214   MutexSet mset;
215   uptr tag = kExternalTagNone;
216   bool res =
217       RestoreStack(thr->tid, v3::EventType::kAccessExt, thr->sid, thr->epoch,
218                    0x3000, 8, kAccessRead, &stk, &mset, &tag);
219   CHECK(res);
220   CHECK_EQ(stk.size, 4);
221   CHECK_EQ(stk.trace[0], 0x1000);
222   CHECK_EQ(stk.trace[1], 0x2000);
223   CHECK_EQ(stk.trace[2], 0x4000);
224   CHECK_EQ(stk.trace[3], 0x2002);
225   CHECK_EQ(mset.Size(), 2);
226   CHECK_EQ(mset.Get(0).addr, 0x5000);
227   CHECK_EQ(mset.Get(0).stack_id, 0x6000);
228   CHECK_EQ(mset.Get(0).write, true);
229   CHECK_EQ(mset.Get(1).addr, 0x5001);
230   CHECK_EQ(mset.Get(1).stack_id, 0x6001);
231   CHECK_EQ(mset.Get(1).write, false);
232 }
233 
234 }  // namespace __tsan
235