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(ml: l);
22}
23
24TEST_F(ThreadSanitizer, SimpleWriteWrite) {
25 ScopedThread t1, t2;
26 MemLoc l1, l2;
27 t1.Write1(ml: l1);
28 t2.Write1(ml: l2);
29}
30
31TEST_F(ThreadSanitizer, WriteWriteRace) {
32 ScopedThread t1, t2;
33 MemLoc l;
34 t1.Write1(ml: l);
35 t2.Write1(ml: l, expect_race: true);
36}
37
38TEST_F(ThreadSanitizer, ReadWriteRace) {
39 ScopedThread t1, t2;
40 MemLoc l;
41 t1.Read1(ml: l);
42 t2.Write1(ml: l, expect_race: true);
43}
44
45TEST_F(ThreadSanitizer, WriteReadRace) {
46 ScopedThread t1, t2;
47 MemLoc l;
48 t1.Write1(ml: l);
49 t2.Read1(ml: l, expect_race: true);
50}
51
52TEST_F(ThreadSanitizer, ReadReadNoRace) {
53 ScopedThread t1, t2;
54 MemLoc l;
55 t1.Read1(ml: l);
56 t2.Read1(ml: l);
57}
58
59TEST_F(ThreadSanitizer, WriteThenRead) {
60 MemLoc l;
61 ScopedThread t1, t2;
62 t1.Write1(ml: l);
63 t1.Read1(ml: l);
64 t2.Read1(ml: l, expect_race: 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(ml: l);
76
77 t1.Lock(m);
78 t1.Read8(ml: l);
79 t1.Unlock(m);
80
81 t2.Read8(ml: l, expect_race: 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(ml: l);
96 t1.Unlock(m);
97
98 t1.Read8(ml: l);
99
100 t2.Read8(ml: l, expect_race: true);
101 }
102 t0.Destroy(m);
103}
104
105
106TEST_F(ThreadSanitizer, RaceWithOffset) {
107 ScopedThread t1, t2;
108 {
109 MemLoc l;
110 t1.Access(addr: l.loc(), is_write: true, size: 8, expect_race: false);
111 t2.Access(addr: (char*)l.loc() + 4, is_write: true, size: 4, expect_race: true);
112 }
113 {
114 MemLoc l;
115 t1.Access(addr: l.loc(), is_write: true, size: 8, expect_race: false);
116 t2.Access(addr: (char*)l.loc() + 7, is_write: true, size: 1, expect_race: true);
117 }
118 {
119 MemLoc l;
120 t1.Access(addr: (char*)l.loc() + 4, is_write: true, size: 4, expect_race: false);
121 t2.Access(addr: (char*)l.loc() + 4, is_write: true, size: 2, expect_race: true);
122 }
123 {
124 MemLoc l;
125 t1.Access(addr: (char*)l.loc() + 4, is_write: true, size: 4, expect_race: false);
126 t2.Access(addr: (char*)l.loc() + 6, is_write: true, size: 2, expect_race: true);
127 }
128 {
129 MemLoc l;
130 t1.Access(addr: (char*)l.loc() + 3, is_write: true, size: 2, expect_race: false);
131 t2.Access(addr: (char*)l.loc() + 4, is_write: true, size: 1, expect_race: true);
132 }
133 {
134 MemLoc l;
135 t1.Access(addr: (char*)l.loc() + 1, is_write: true, size: 8, expect_race: false);
136 t2.Access(addr: (char*)l.loc() + 3, is_write: true, size: 1, expect_race: true);
137 }
138}
139
140TEST_F(ThreadSanitizer, RaceWithOffset2) {
141 ScopedThread t1, t2;
142 {
143 MemLoc l;
144 t1.Access(addr: (char*)l.loc(), is_write: true, size: 4, expect_race: false);
145 t2.Access(addr: (char*)l.loc() + 2, is_write: true, size: 1, expect_race: true);
146 }
147 {
148 MemLoc l;
149 t1.Access(addr: (char*)l.loc() + 2, is_write: true, size: 1, expect_race: false);
150 t2.Access(addr: (char*)l.loc(), is_write: true, size: 4, expect_race: true);
151 }
152}
153
154TEST_F(ThreadSanitizer, NoRaceWithOffset) {
155 ScopedThread t1, t2;
156 {
157 MemLoc l;
158 t1.Access(addr: l.loc(), is_write: true, size: 4, expect_race: false);
159 t2.Access(addr: (char*)l.loc() + 4, is_write: true, size: 4, expect_race: false);
160 }
161 {
162 MemLoc l;
163 t1.Access(addr: (char*)l.loc() + 3, is_write: true, size: 2, expect_race: false);
164 t2.Access(addr: (char*)l.loc() + 1, is_write: true, size: 2, expect_race: false);
165 t2.Access(addr: (char*)l.loc() + 5, is_write: true, size: 2, expect_race: false);
166 }
167}
168
169TEST_F(ThreadSanitizer, RaceWithDeadThread) {
170 MemLoc l;
171 ScopedThread t;
172 ScopedThread().Write1(ml: l);
173 t.Write1(ml: l, expect_race: 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, new_val: val);
182 t2.Read8(ml: 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, new_val: val2);
191 t2.Read8(ml: vptr, expect_race: 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(pc: &foo);
212 t2.Call(pc: &bar);
213 t2.Write1(ml: l);
214 }
215 t1.Write1(ml: l, expect_race: 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(addr: &ClassWithStatic::Data, is_write: true, size: 4, expect_race: false);
229 t1.Call(pc: &foobarbaz);
230 t1.Access(addr: &ClassWithStatic::Data, is_write: true, size: 2, expect_race: true);
231 t1.Return();
232}
233

source code of compiler-rt/lib/tsan/tests/rtl/tsan_mop.cpp