1 //===-- tsan_mop.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_interface.h"
13 #include "tsan_test_util.h"
14 #include "gtest/gtest.h"
15 #include <stddef.h>
16 #include <stdint.h>
17 
18 TEST(ThreadSanitizer, SimpleWrite) {
19   ScopedThread t;
20   MemLoc l;
21   t.Write1(l);
22 }
23 
24 TEST(ThreadSanitizer, SimpleWriteWrite) {
25   ScopedThread t1, t2;
26   MemLoc l1, l2;
27   t1.Write1(l1);
28   t2.Write1(l2);
29 }
30 
31 TEST(ThreadSanitizer, WriteWriteRace) {
32   ScopedThread t1, t2;
33   MemLoc l;
34   t1.Write1(l);
35   t2.Write1(l, true);
36 }
37 
38 TEST(ThreadSanitizer, ReadWriteRace) {
39   ScopedThread t1, t2;
40   MemLoc l;
41   t1.Read1(l);
42   t2.Write1(l, true);
43 }
44 
45 TEST(ThreadSanitizer, WriteReadRace) {
46   ScopedThread t1, t2;
47   MemLoc l;
48   t1.Write1(l);
49   t2.Read1(l, true);
50 }
51 
52 TEST(ThreadSanitizer, ReadReadNoRace) {
53   ScopedThread t1, t2;
54   MemLoc l;
55   t1.Read1(l);
56   t2.Read1(l);
57 }
58 
59 TEST(ThreadSanitizer, WriteThenRead) {
60   MemLoc l;
61   ScopedThread t1, t2;
62   t1.Write1(l);
63   t1.Read1(l);
64   t2.Read1(l, true);
65 }
66 
67 TEST(ThreadSanitizer, WriteThenLockedRead) {
68   Mutex m(Mutex::RW);
69   MainThread t0;
70   t0.Create(m);
71   MemLoc l;
72   {
73     ScopedThread t1, t2;
74 
75     t1.Write8(l);
76 
77     t1.Lock(m);
78     t1.Read8(l);
79     t1.Unlock(m);
80 
81     t2.Read8(l, true);
82   }
83   t0.Destroy(m);
84 }
85 
86 TEST(ThreadSanitizer, LockedWriteThenRead) {
87   Mutex m(Mutex::RW);
88   MainThread t0;
89   t0.Create(m);
90   MemLoc l;
91   {
92     ScopedThread t1, t2;
93 
94     t1.Lock(m);
95     t1.Write8(l);
96     t1.Unlock(m);
97 
98     t1.Read8(l);
99 
100     t2.Read8(l, true);
101   }
102   t0.Destroy(m);
103 }
104 
105 
106 TEST(ThreadSanitizer, RaceWithOffset) {
107   ScopedThread t1, t2;
108   {
109     MemLoc l;
110     t1.Access(l.loc(), true, 8, false);
111     t2.Access((char*)l.loc() + 4, true, 4, true);
112   }
113   {
114     MemLoc l;
115     t1.Access(l.loc(), true, 8, false);
116     t2.Access((char*)l.loc() + 7, true, 1, true);
117   }
118   {
119     MemLoc l;
120     t1.Access((char*)l.loc() + 4, true, 4, false);
121     t2.Access((char*)l.loc() + 4, true, 2, true);
122   }
123   {
124     MemLoc l;
125     t1.Access((char*)l.loc() + 4, true, 4, false);
126     t2.Access((char*)l.loc() + 6, true, 2, true);
127   }
128   {
129     MemLoc l;
130     t1.Access((char*)l.loc() + 3, true, 2, false);
131     t2.Access((char*)l.loc() + 4, true, 1, true);
132   }
133   {
134     MemLoc l;
135     t1.Access((char*)l.loc() + 1, true, 8, false);
136     t2.Access((char*)l.loc() + 3, true, 1, true);
137   }
138 }
139 
140 TEST(ThreadSanitizer, RaceWithOffset2) {
141   ScopedThread t1, t2;
142   {
143     MemLoc l;
144     t1.Access((char*)l.loc(), true, 4, false);
145     t2.Access((char*)l.loc() + 2, true, 1, true);
146   }
147   {
148     MemLoc l;
149     t1.Access((char*)l.loc() + 2, true, 1, false);
150     t2.Access((char*)l.loc(), true, 4, true);
151   }
152 }
153 
154 TEST(ThreadSanitizer, NoRaceWithOffset) {
155   ScopedThread t1, t2;
156   {
157     MemLoc l;
158     t1.Access(l.loc(), true, 4, false);
159     t2.Access((char*)l.loc() + 4, true, 4, false);
160   }
161   {
162     MemLoc l;
163     t1.Access((char*)l.loc() + 3, true, 2, false);
164     t2.Access((char*)l.loc() + 1, true, 2, false);
165     t2.Access((char*)l.loc() + 5, true, 2, false);
166   }
167 }
168 
169 TEST(ThreadSanitizer, RaceWithDeadThread) {
170   MemLoc l;
171   ScopedThread t;
172   ScopedThread().Write1(l);
173   t.Write1(l, true);
174 }
175 
176 TEST(ThreadSanitizer, BenignRaceOnVptr) {
177   void *vptr_storage;
178   MemLoc vptr(&vptr_storage), val;
179   vptr_storage = val.loc();
180   ScopedThread t1, t2;
181   t1.VptrUpdate(vptr, val);
182   t2.Read8(vptr);
183 }
184 
185 TEST(ThreadSanitizer, HarmfulRaceOnVptr) {
186   void *vptr_storage;
187   MemLoc vptr(&vptr_storage), val1, val2;
188   vptr_storage = val1.loc();
189   ScopedThread t1, t2;
190   t1.VptrUpdate(vptr, val2);
191   t2.Read8(vptr, true);
192 }
193 
194 static void foo() {
195   volatile int x = 42;
196   int x2 = x;
197   (void)x2;
198 }
199 
200 static void bar() {
201   volatile int x = 43;
202   int x2 = x;
203   (void)x2;
204 }
205 
206 TEST(ThreadSanitizer, ReportDeadThread) {
207   MemLoc l;
208   ScopedThread t1;
209   {
210     ScopedThread t2;
211     t2.Call(&foo);
212     t2.Call(&bar);
213     t2.Write1(l);
214   }
215   t1.Write1(l, true);
216 }
217 
218 struct ClassWithStatic {
219   static int Data[4];
220 };
221 
222 int ClassWithStatic::Data[4];
223 
224 static void foobarbaz() {}
225 
226 TEST(ThreadSanitizer, ReportRace) {
227   ScopedThread t1;
228   MainThread().Access(&ClassWithStatic::Data, true, 4, false);
229   t1.Call(&foobarbaz);
230   t1.Access(&ClassWithStatic::Data, true, 2, true);
231   t1.Return();
232 }
233