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