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
18TEST_F(ThreadSanitizer, SimpleWrite) {
19  ScopedThread t;
20  MemLoc l;
21  t.Write1(l);
22}
23
24TEST_F(ThreadSanitizer, SimpleWriteWrite) {
25  ScopedThread t1, t2;
26  MemLoc l1, l2;
27  t1.Write1(l1);
28  t2.Write1(l2);
29}
30
31TEST_F(ThreadSanitizer, WriteWriteRace) {
32  ScopedThread t1, t2;
33  MemLoc l;
34  t1.Write1(l);
35  t2.Write1(l, true);
36}
37
38TEST_F(ThreadSanitizer, ReadWriteRace) {
39  ScopedThread t1, t2;
40  MemLoc l;
41  t1.Read1(l);
42  t2.Write1(l, true);
43}
44
45TEST_F(ThreadSanitizer, WriteReadRace) {
46  ScopedThread t1, t2;
47  MemLoc l;
48  t1.Write1(l);
49  t2.Read1(l, true);
50}
51
52TEST_F(ThreadSanitizer, ReadReadNoRace) {
53  ScopedThread t1, t2;
54  MemLoc l;
55  t1.Read1(l);
56  t2.Read1(l);
57}
58
59TEST_F(ThreadSanitizer, WriteThenRead) {
60  MemLoc l;
61  ScopedThread t1, t2;
62  t1.Write1(l);
63  t1.Read1(l);
64  t2.Read1(l, true);
65}
66
67TEST_F(ThreadSanitizer, WriteThenLockedRead) {
68  UserMutex m(UserMutex::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
86TEST_F(ThreadSanitizer, LockedWriteThenRead) {
87  UserMutex m(UserMutex::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
106TEST_F(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
140TEST_F(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
154TEST_F(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
169TEST_F(ThreadSanitizer, RaceWithDeadThread) {
170  MemLoc l;
171  ScopedThread t;
172  ScopedThread().Write1(l);
173  t.Write1(l, true);
174}
175
176TEST_F(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
185TEST_F(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
194static void foo() {
195  volatile int x = 42;
196  int x2 = x;
197  (void)x2;
198}
199
200static void bar() {
201  volatile int x = 43;
202  int x2 = x;
203  (void)x2;
204}
205
206TEST_F(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
218struct ClassWithStatic {
219  static int Data[4];
220};
221
222int ClassWithStatic::Data[4];
223
224static void foobarbaz() {}
225
226TEST_F(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