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