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 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 86 TEST(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 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