forked from OSchip/llvm-project
234 lines
4.4 KiB
C++
234 lines
4.4 KiB
C++
//===-- 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();
|
|
}
|