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