//===-- tsan_mop.cc -------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "tsan_interface.h" #include "tsan_test_util.h" #include "gtest/gtest.h" #include <stddef.h> #include <stdint.h> TEST(ThreadSanitizer, SimpleWrite) { ScopedThread t; MemLoc l; t.Write1(l); } TEST(ThreadSanitizer, SimpleWriteWrite) { ScopedThread t1, t2; MemLoc l1, l2; t1.Write1(l1); t2.Write1(l2); } TEST(ThreadSanitizer, WriteWriteRace) { ScopedThread t1, t2; MemLoc l; t1.Write1(l); t2.Write1(l, true); } TEST(ThreadSanitizer, ReadWriteRace) { ScopedThread t1, t2; MemLoc l; t1.Read1(l); t2.Write1(l, true); } TEST(ThreadSanitizer, WriteReadRace) { ScopedThread t1, t2; MemLoc l; t1.Write1(l); t2.Read1(l, true); } TEST(ThreadSanitizer, ReadReadNoRace) { ScopedThread t1, t2; MemLoc l; t1.Read1(l); t2.Read1(l); } TEST(ThreadSanitizer, WriteThenRead) { MemLoc l; ScopedThread t1, t2; t1.Write1(l); t1.Read1(l); t2.Read1(l, true); } TEST(ThreadSanitizer, WriteThenLockedRead) { Mutex m(Mutex::RW); MainThread t0; t0.Create(m); MemLoc l; { ScopedThread t1, t2; t1.Write8(l); t1.Lock(m); t1.Read8(l); t1.Unlock(m); t2.Read8(l, true); } t0.Destroy(m); } TEST(ThreadSanitizer, LockedWriteThenRead) { Mutex m(Mutex::RW); MainThread t0; t0.Create(m); MemLoc l; { ScopedThread t1, t2; t1.Lock(m); t1.Write8(l); t1.Unlock(m); t1.Read8(l); t2.Read8(l, true); } t0.Destroy(m); } TEST(ThreadSanitizer, RaceWithOffset) { ScopedThread t1, t2; { MemLoc l; t1.Access(l.loc(), true, 8, false); t2.Access((char*)l.loc() + 4, true, 4, true); } { MemLoc l; t1.Access(l.loc(), true, 8, false); t2.Access((char*)l.loc() + 7, true, 1, true); } { MemLoc l; t1.Access((char*)l.loc() + 4, true, 4, false); t2.Access((char*)l.loc() + 4, true, 2, true); } { MemLoc l; t1.Access((char*)l.loc() + 4, true, 4, false); t2.Access((char*)l.loc() + 6, true, 2, true); } { MemLoc l; t1.Access((char*)l.loc() + 3, true, 2, false); t2.Access((char*)l.loc() + 4, true, 1, true); } { MemLoc l; t1.Access((char*)l.loc() + 1, true, 8, false); t2.Access((char*)l.loc() + 3, true, 1, true); } } TEST(ThreadSanitizer, RaceWithOffset2) { ScopedThread t1, t2; { MemLoc l; t1.Access((char*)l.loc(), true, 4, false); t2.Access((char*)l.loc() + 2, true, 1, true); } { MemLoc l; t1.Access((char*)l.loc() + 2, true, 1, false); t2.Access((char*)l.loc(), true, 4, true); } } TEST(ThreadSanitizer, NoRaceWithOffset) { ScopedThread t1, t2; { MemLoc l; t1.Access(l.loc(), true, 4, false); t2.Access((char*)l.loc() + 4, true, 4, false); } { MemLoc l; t1.Access((char*)l.loc() + 3, true, 2, false); t2.Access((char*)l.loc() + 1, true, 2, false); t2.Access((char*)l.loc() + 5, true, 2, false); } } TEST(ThreadSanitizer, RaceWithDeadThread) { MemLoc l; ScopedThread t; ScopedThread().Write1(l); t.Write1(l, true); } TEST(ThreadSanitizer, BenignRaceOnVptr) { void *vptr_storage; MemLoc vptr(&vptr_storage), val; vptr_storage = val.loc(); ScopedThread t1, t2; t1.VptrUpdate(vptr, val); t2.Read8(vptr); } TEST(ThreadSanitizer, HarmfulRaceOnVptr) { void *vptr_storage; MemLoc vptr(&vptr_storage), val1, val2; vptr_storage = val1.loc(); ScopedThread t1, t2; t1.VptrUpdate(vptr, val2); t2.Read8(vptr, true); } static void foo() { volatile int x = 42; int x2 = x; (void)x2; } static void bar() { volatile int x = 43; int x2 = x; (void)x2; } TEST(ThreadSanitizer, ReportDeadThread) { MemLoc l; ScopedThread t1; { ScopedThread t2; t2.Call(&foo); t2.Call(&bar); t2.Write1(l); } t1.Write1(l, true); } struct ClassWithStatic { static int Data[4]; }; int ClassWithStatic::Data[4]; static void foobarbaz() {} TEST(ThreadSanitizer, ReportRace) { ScopedThread t1; MainThread().Access(&ClassWithStatic::Data, true, 4, false); t1.Call(&foobarbaz); t1.Access(&ClassWithStatic::Data, true, 2, true); t1.Return(); }