| //===-- 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(); |
| } |