diff options
Diffstat (limited to 'src/runtime/race/testdata')
21 files changed, 6079 insertions, 0 deletions
diff --git a/src/runtime/race/testdata/atomic_test.go b/src/runtime/race/testdata/atomic_test.go new file mode 100644 index 0000000..4ce7260 --- /dev/null +++ b/src/runtime/race/testdata/atomic_test.go @@ -0,0 +1,325 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "runtime" + "sync" + "sync/atomic" + "testing" + "unsafe" +) + +func TestNoRaceAtomicAddInt64(t *testing.T) { + var x1, x2 int8 + _ = x1 + x2 + var s int64 + ch := make(chan bool, 2) + go func() { + x1 = 1 + if atomic.AddInt64(&s, 1) == 2 { + x2 = 1 + } + ch <- true + }() + go func() { + x2 = 1 + if atomic.AddInt64(&s, 1) == 2 { + x1 = 1 + } + ch <- true + }() + <-ch + <-ch +} + +func TestRaceAtomicAddInt64(t *testing.T) { + var x1, x2 int8 + _ = x1 + x2 + var s int64 + ch := make(chan bool, 2) + go func() { + x1 = 1 + if atomic.AddInt64(&s, 1) == 1 { + x2 = 1 + } + ch <- true + }() + go func() { + x2 = 1 + if atomic.AddInt64(&s, 1) == 1 { + x1 = 1 + } + ch <- true + }() + <-ch + <-ch +} + +func TestNoRaceAtomicAddInt32(t *testing.T) { + var x1, x2 int8 + _ = x1 + x2 + var s int32 + ch := make(chan bool, 2) + go func() { + x1 = 1 + if atomic.AddInt32(&s, 1) == 2 { + x2 = 1 + } + ch <- true + }() + go func() { + x2 = 1 + if atomic.AddInt32(&s, 1) == 2 { + x1 = 1 + } + ch <- true + }() + <-ch + <-ch +} + +func TestNoRaceAtomicLoadAddInt32(t *testing.T) { + var x int64 + _ = x + var s int32 + go func() { + x = 2 + atomic.AddInt32(&s, 1) + }() + for atomic.LoadInt32(&s) != 1 { + runtime.Gosched() + } + x = 1 +} + +func TestNoRaceAtomicLoadStoreInt32(t *testing.T) { + var x int64 + _ = x + var s int32 + go func() { + x = 2 + atomic.StoreInt32(&s, 1) + }() + for atomic.LoadInt32(&s) != 1 { + runtime.Gosched() + } + x = 1 +} + +func TestNoRaceAtomicStoreCASInt32(t *testing.T) { + var x int64 + _ = x + var s int32 + go func() { + x = 2 + atomic.StoreInt32(&s, 1) + }() + for !atomic.CompareAndSwapInt32(&s, 1, 0) { + runtime.Gosched() + } + x = 1 +} + +func TestNoRaceAtomicCASLoadInt32(t *testing.T) { + var x int64 + _ = x + var s int32 + go func() { + x = 2 + if !atomic.CompareAndSwapInt32(&s, 0, 1) { + panic("") + } + }() + for atomic.LoadInt32(&s) != 1 { + runtime.Gosched() + } + x = 1 +} + +func TestNoRaceAtomicCASCASInt32(t *testing.T) { + var x int64 + _ = x + var s int32 + go func() { + x = 2 + if !atomic.CompareAndSwapInt32(&s, 0, 1) { + panic("") + } + }() + for !atomic.CompareAndSwapInt32(&s, 1, 0) { + runtime.Gosched() + } + x = 1 +} + +func TestNoRaceAtomicCASCASInt32_2(t *testing.T) { + var x1, x2 int8 + _ = x1 + x2 + var s int32 + ch := make(chan bool, 2) + go func() { + x1 = 1 + if !atomic.CompareAndSwapInt32(&s, 0, 1) { + x2 = 1 + } + ch <- true + }() + go func() { + x2 = 1 + if !atomic.CompareAndSwapInt32(&s, 0, 1) { + x1 = 1 + } + ch <- true + }() + <-ch + <-ch +} + +func TestNoRaceAtomicLoadInt64(t *testing.T) { + var x int32 + _ = x + var s int64 + go func() { + x = 2 + atomic.AddInt64(&s, 1) + }() + for atomic.LoadInt64(&s) != 1 { + runtime.Gosched() + } + x = 1 +} + +func TestNoRaceAtomicCASCASUInt64(t *testing.T) { + var x int64 + _ = x + var s uint64 + go func() { + x = 2 + if !atomic.CompareAndSwapUint64(&s, 0, 1) { + panic("") + } + }() + for !atomic.CompareAndSwapUint64(&s, 1, 0) { + runtime.Gosched() + } + x = 1 +} + +func TestNoRaceAtomicLoadStorePointer(t *testing.T) { + var x int64 + _ = x + var s unsafe.Pointer + var y int = 2 + var p unsafe.Pointer = unsafe.Pointer(&y) + go func() { + x = 2 + atomic.StorePointer(&s, p) + }() + for atomic.LoadPointer(&s) != p { + runtime.Gosched() + } + x = 1 +} + +func TestNoRaceAtomicStoreCASUint64(t *testing.T) { + var x int64 + _ = x + var s uint64 + go func() { + x = 2 + atomic.StoreUint64(&s, 1) + }() + for !atomic.CompareAndSwapUint64(&s, 1, 0) { + runtime.Gosched() + } + x = 1 +} + +func TestRaceAtomicStoreLoad(t *testing.T) { + c := make(chan bool) + var a uint64 + go func() { + atomic.StoreUint64(&a, 1) + c <- true + }() + _ = a + <-c +} + +func TestRaceAtomicLoadStore(t *testing.T) { + c := make(chan bool) + var a uint64 + go func() { + _ = atomic.LoadUint64(&a) + c <- true + }() + a = 1 + <-c +} + +func TestRaceAtomicAddLoad(t *testing.T) { + c := make(chan bool) + var a uint64 + go func() { + atomic.AddUint64(&a, 1) + c <- true + }() + _ = a + <-c +} + +func TestRaceAtomicAddStore(t *testing.T) { + c := make(chan bool) + var a uint64 + go func() { + atomic.AddUint64(&a, 1) + c <- true + }() + a = 42 + <-c +} + +// A nil pointer in an atomic operation should not deadlock +// the rest of the program. Used to hang indefinitely. +func TestNoRaceAtomicCrash(t *testing.T) { + var mutex sync.Mutex + var nilptr *int32 + panics := 0 + defer func() { + if x := recover(); x != nil { + mutex.Lock() + panics++ + mutex.Unlock() + } else { + panic("no panic") + } + }() + atomic.AddInt32(nilptr, 1) +} + +func TestNoRaceDeferAtomicStore(t *testing.T) { + // Test that when an atomic function is deferred directly, the + // GC scans it correctly. See issue 42599. + type foo struct { + bar int64 + } + + var doFork func(f *foo, depth int) + doFork = func(f *foo, depth int) { + atomic.StoreInt64(&f.bar, 1) + defer atomic.StoreInt64(&f.bar, 0) + if depth > 0 { + for i := 0; i < 2; i++ { + f2 := &foo{} + go doFork(f2, depth-1) + } + } + runtime.GC() + } + + f := &foo{} + doFork(f, 11) +} diff --git a/src/runtime/race/testdata/cgo_test.go b/src/runtime/race/testdata/cgo_test.go new file mode 100644 index 0000000..211ef7d --- /dev/null +++ b/src/runtime/race/testdata/cgo_test.go @@ -0,0 +1,21 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "internal/testenv" + "os" + "os/exec" + "testing" +) + +func TestNoRaceCgoSync(t *testing.T) { + cmd := exec.Command(testenv.GoToolPath(t), "run", "-race", "cgo_test_main.go") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + t.Fatalf("program exited with error: %v\n", err) + } +} diff --git a/src/runtime/race/testdata/cgo_test_main.go b/src/runtime/race/testdata/cgo_test_main.go new file mode 100644 index 0000000..620cea1 --- /dev/null +++ b/src/runtime/race/testdata/cgo_test_main.go @@ -0,0 +1,30 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +int sync; + +void Notify(void) +{ + __sync_fetch_and_add(&sync, 1); +} + +void Wait(void) +{ + while(__sync_fetch_and_add(&sync, 0) == 0) {} +} +*/ +import "C" + +func main() { + data := 0 + go func() { + data = 1 + C.Notify() + }() + C.Wait() + _ = data +} diff --git a/src/runtime/race/testdata/chan_test.go b/src/runtime/race/testdata/chan_test.go new file mode 100644 index 0000000..e39ad4f --- /dev/null +++ b/src/runtime/race/testdata/chan_test.go @@ -0,0 +1,787 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "runtime" + "testing" + "time" +) + +func TestNoRaceChanSync(t *testing.T) { + v := 0 + _ = v + c := make(chan int) + go func() { + v = 1 + c <- 0 + }() + <-c + v = 2 +} + +func TestNoRaceChanSyncRev(t *testing.T) { + v := 0 + _ = v + c := make(chan int) + go func() { + c <- 0 + v = 2 + }() + v = 1 + <-c +} + +func TestNoRaceChanAsync(t *testing.T) { + v := 0 + _ = v + c := make(chan int, 10) + go func() { + v = 1 + c <- 0 + }() + <-c + v = 2 +} + +func TestRaceChanAsyncRev(t *testing.T) { + v := 0 + _ = v + c := make(chan int, 10) + go func() { + c <- 0 + v = 1 + }() + v = 2 + <-c +} + +func TestNoRaceChanAsyncCloseRecv(t *testing.T) { + v := 0 + _ = v + c := make(chan int, 10) + go func() { + v = 1 + close(c) + }() + func() { + defer func() { + recover() + v = 2 + }() + <-c + }() +} + +func TestNoRaceChanAsyncCloseRecv2(t *testing.T) { + v := 0 + _ = v + c := make(chan int, 10) + go func() { + v = 1 + close(c) + }() + _, _ = <-c + v = 2 +} + +func TestNoRaceChanAsyncCloseRecv3(t *testing.T) { + v := 0 + _ = v + c := make(chan int, 10) + go func() { + v = 1 + close(c) + }() + for range c { + } + v = 2 +} + +func TestNoRaceChanSyncCloseRecv(t *testing.T) { + v := 0 + _ = v + c := make(chan int) + go func() { + v = 1 + close(c) + }() + func() { + defer func() { + recover() + v = 2 + }() + <-c + }() +} + +func TestNoRaceChanSyncCloseRecv2(t *testing.T) { + v := 0 + _ = v + c := make(chan int) + go func() { + v = 1 + close(c) + }() + _, _ = <-c + v = 2 +} + +func TestNoRaceChanSyncCloseRecv3(t *testing.T) { + v := 0 + _ = v + c := make(chan int) + go func() { + v = 1 + close(c) + }() + for range c { + } + v = 2 +} + +func TestRaceChanSyncCloseSend(t *testing.T) { + v := 0 + _ = v + c := make(chan int) + go func() { + v = 1 + close(c) + }() + func() { + defer func() { + recover() + }() + c <- 0 + }() + v = 2 +} + +func TestRaceChanAsyncCloseSend(t *testing.T) { + v := 0 + _ = v + c := make(chan int, 10) + go func() { + v = 1 + close(c) + }() + func() { + defer func() { + recover() + }() + for { + c <- 0 + } + }() + v = 2 +} + +func TestRaceChanCloseClose(t *testing.T) { + compl := make(chan bool, 2) + v1 := 0 + v2 := 0 + _ = v1 + v2 + c := make(chan int) + go func() { + defer func() { + if recover() != nil { + v2 = 2 + } + compl <- true + }() + v1 = 1 + close(c) + }() + go func() { + defer func() { + if recover() != nil { + v1 = 2 + } + compl <- true + }() + v2 = 1 + close(c) + }() + <-compl + <-compl +} + +func TestRaceChanSendLen(t *testing.T) { + v := 0 + _ = v + c := make(chan int, 10) + go func() { + v = 1 + c <- 1 + }() + for len(c) == 0 { + runtime.Gosched() + } + v = 2 +} + +func TestRaceChanRecvLen(t *testing.T) { + v := 0 + _ = v + c := make(chan int, 10) + c <- 1 + go func() { + v = 1 + <-c + }() + for len(c) != 0 { + runtime.Gosched() + } + v = 2 +} + +func TestRaceChanSendSend(t *testing.T) { + compl := make(chan bool, 2) + v1 := 0 + v2 := 0 + _ = v1 + v2 + c := make(chan int, 1) + go func() { + v1 = 1 + select { + case c <- 1: + default: + v2 = 2 + } + compl <- true + }() + go func() { + v2 = 1 + select { + case c <- 1: + default: + v1 = 2 + } + compl <- true + }() + <-compl + <-compl +} + +func TestNoRaceChanPtr(t *testing.T) { + type msg struct { + x int + } + c := make(chan *msg) + go func() { + c <- &msg{1} + }() + m := <-c + m.x = 2 +} + +func TestRaceChanWrongSend(t *testing.T) { + v1 := 0 + v2 := 0 + _ = v1 + v2 + c := make(chan int, 2) + go func() { + v1 = 1 + c <- 1 + }() + go func() { + v2 = 2 + c <- 2 + }() + time.Sleep(1e7) + if <-c == 1 { + v2 = 3 + } else { + v1 = 3 + } +} + +func TestRaceChanWrongClose(t *testing.T) { + v1 := 0 + v2 := 0 + _ = v1 + v2 + c := make(chan int, 1) + done := make(chan bool) + go func() { + defer func() { + recover() + }() + v1 = 1 + c <- 1 + done <- true + }() + go func() { + time.Sleep(1e7) + v2 = 2 + close(c) + done <- true + }() + time.Sleep(2e7) + if _, who := <-c; who { + v2 = 2 + } else { + v1 = 2 + } + <-done + <-done +} + +func TestRaceChanSendClose(t *testing.T) { + compl := make(chan bool, 2) + c := make(chan int, 1) + go func() { + defer func() { + recover() + compl <- true + }() + c <- 1 + }() + go func() { + time.Sleep(10 * time.Millisecond) + close(c) + compl <- true + }() + <-compl + <-compl +} + +func TestRaceChanSendSelectClose(t *testing.T) { + compl := make(chan bool, 2) + c := make(chan int, 1) + c1 := make(chan int) + go func() { + defer func() { + recover() + compl <- true + }() + time.Sleep(10 * time.Millisecond) + select { + case c <- 1: + case <-c1: + } + }() + go func() { + close(c) + compl <- true + }() + <-compl + <-compl +} + +func TestRaceSelectReadWriteAsync(t *testing.T) { + done := make(chan bool) + x := 0 + c1 := make(chan int, 10) + c2 := make(chan int, 10) + c3 := make(chan int) + c2 <- 1 + go func() { + select { + case c1 <- x: // read of x races with... + case c3 <- 1: + } + done <- true + }() + select { + case x = <-c2: // ... write to x here + case c3 <- 1: + } + <-done +} + +func TestRaceSelectReadWriteSync(t *testing.T) { + done := make(chan bool) + x := 0 + c1 := make(chan int) + c2 := make(chan int) + c3 := make(chan int) + // make c1 and c2 ready for communication + go func() { + <-c1 + }() + go func() { + c2 <- 1 + }() + go func() { + select { + case c1 <- x: // read of x races with... + case c3 <- 1: + } + done <- true + }() + select { + case x = <-c2: // ... write to x here + case c3 <- 1: + } + <-done +} + +func TestNoRaceSelectReadWriteAsync(t *testing.T) { + done := make(chan bool) + x := 0 + c1 := make(chan int) + c2 := make(chan int) + go func() { + select { + case c1 <- x: // read of x does not race with... + case c2 <- 1: + } + done <- true + }() + select { + case x = <-c1: // ... write to x here + case c2 <- 1: + } + <-done +} + +func TestRaceChanReadWriteAsync(t *testing.T) { + done := make(chan bool) + c1 := make(chan int, 10) + c2 := make(chan int, 10) + c2 <- 10 + x := 0 + go func() { + c1 <- x // read of x races with... + done <- true + }() + x = <-c2 // ... write to x here + <-done +} + +func TestRaceChanReadWriteSync(t *testing.T) { + done := make(chan bool) + c1 := make(chan int) + c2 := make(chan int) + // make c1 and c2 ready for communication + go func() { + <-c1 + }() + go func() { + c2 <- 10 + }() + x := 0 + go func() { + c1 <- x // read of x races with... + done <- true + }() + x = <-c2 // ... write to x here + <-done +} + +func TestNoRaceChanReadWriteAsync(t *testing.T) { + done := make(chan bool) + c1 := make(chan int, 10) + x := 0 + go func() { + c1 <- x // read of x does not race with... + done <- true + }() + x = <-c1 // ... write to x here + <-done +} + +func TestNoRaceProducerConsumerUnbuffered(t *testing.T) { + type Task struct { + f func() + done chan bool + } + + queue := make(chan Task) + + go func() { + t := <-queue + t.f() + t.done <- true + }() + + doit := func(f func()) { + done := make(chan bool, 1) + queue <- Task{f, done} + <-done + } + + x := 0 + doit(func() { + x = 1 + }) + _ = x +} + +func TestRaceChanItselfSend(t *testing.T) { + compl := make(chan bool, 1) + c := make(chan int, 10) + go func() { + c <- 0 + compl <- true + }() + c = make(chan int, 20) + <-compl +} + +func TestRaceChanItselfRecv(t *testing.T) { + compl := make(chan bool, 1) + c := make(chan int, 10) + c <- 1 + go func() { + <-c + compl <- true + }() + time.Sleep(1e7) + c = make(chan int, 20) + <-compl +} + +func TestRaceChanItselfNil(t *testing.T) { + c := make(chan int, 10) + go func() { + c <- 0 + }() + time.Sleep(1e7) + c = nil + _ = c +} + +func TestRaceChanItselfClose(t *testing.T) { + compl := make(chan bool, 1) + c := make(chan int) + go func() { + close(c) + compl <- true + }() + c = make(chan int) + <-compl +} + +func TestRaceChanItselfLen(t *testing.T) { + compl := make(chan bool, 1) + c := make(chan int) + go func() { + _ = len(c) + compl <- true + }() + c = make(chan int) + <-compl +} + +func TestRaceChanItselfCap(t *testing.T) { + compl := make(chan bool, 1) + c := make(chan int) + go func() { + _ = cap(c) + compl <- true + }() + c = make(chan int) + <-compl +} + +func TestNoRaceChanCloseLen(t *testing.T) { + c := make(chan int, 10) + r := make(chan int, 10) + go func() { + r <- len(c) + }() + go func() { + close(c) + r <- 0 + }() + <-r + <-r +} + +func TestNoRaceChanCloseCap(t *testing.T) { + c := make(chan int, 10) + r := make(chan int, 10) + go func() { + r <- cap(c) + }() + go func() { + close(c) + r <- 0 + }() + <-r + <-r +} + +func TestRaceChanCloseSend(t *testing.T) { + compl := make(chan bool, 1) + c := make(chan int, 10) + go func() { + close(c) + compl <- true + }() + c <- 0 + <-compl +} + +func TestNoRaceChanMutex(t *testing.T) { + done := make(chan struct{}) + mtx := make(chan struct{}, 1) + data := 0 + _ = data + go func() { + mtx <- struct{}{} + data = 42 + <-mtx + done <- struct{}{} + }() + mtx <- struct{}{} + data = 43 + <-mtx + <-done +} + +func TestNoRaceSelectMutex(t *testing.T) { + done := make(chan struct{}) + mtx := make(chan struct{}, 1) + aux := make(chan bool) + data := 0 + _ = data + go func() { + select { + case mtx <- struct{}{}: + case <-aux: + } + data = 42 + select { + case <-mtx: + case <-aux: + } + done <- struct{}{} + }() + select { + case mtx <- struct{}{}: + case <-aux: + } + data = 43 + select { + case <-mtx: + case <-aux: + } + <-done +} + +func TestRaceChanSem(t *testing.T) { + done := make(chan struct{}) + mtx := make(chan bool, 2) + data := 0 + _ = data + go func() { + mtx <- true + data = 42 + <-mtx + done <- struct{}{} + }() + mtx <- true + data = 43 + <-mtx + <-done +} + +func TestNoRaceChanWaitGroup(t *testing.T) { + const N = 10 + chanWg := make(chan bool, N/2) + data := make([]int, N) + for i := 0; i < N; i++ { + chanWg <- true + go func(i int) { + data[i] = 42 + <-chanWg + }(i) + } + for i := 0; i < cap(chanWg); i++ { + chanWg <- true + } + for i := 0; i < N; i++ { + _ = data[i] + } +} + +// Test that sender synchronizes with receiver even if the sender was blocked. +func TestNoRaceBlockedSendSync(t *testing.T) { + c := make(chan *int, 1) + c <- nil + go func() { + i := 42 + c <- &i + }() + // Give the sender time to actually block. + // This sleep is completely optional: race report must not be printed + // regardless of whether the sender actually blocks or not. + // It cannot lead to flakiness. + time.Sleep(10 * time.Millisecond) + <-c + p := <-c + if *p != 42 { + t.Fatal() + } +} + +// The same as TestNoRaceBlockedSendSync above, but sender unblock happens in a select. +func TestNoRaceBlockedSelectSendSync(t *testing.T) { + c := make(chan *int, 1) + c <- nil + go func() { + i := 42 + c <- &i + }() + time.Sleep(10 * time.Millisecond) + <-c + select { + case p := <-c: + if *p != 42 { + t.Fatal() + } + case <-make(chan int): + } +} + +// Test that close synchronizes with a read from the empty closed channel. +// See https://golang.org/issue/36714. +func TestNoRaceCloseHappensBeforeRead(t *testing.T) { + for i := 0; i < 100; i++ { + var loc int + var write = make(chan struct{}) + var read = make(chan struct{}) + + go func() { + select { + case <-write: + _ = loc + default: + } + close(read) + }() + + go func() { + loc = 1 + close(write) + }() + + <-read + } +} + +// Test that we call the proper race detector function when c.elemsize==0. +// See https://github.com/golang/go/issues/42598 +func TestNoRaceElemetSize0(t *testing.T) { + var x, y int + var c = make(chan struct{}, 2) + c <- struct{}{} + c <- struct{}{} + go func() { + x += 1 + <-c + }() + go func() { + y += 1 + <-c + }() + time.Sleep(10 * time.Millisecond) + c <- struct{}{} + c <- struct{}{} + x += 1 + y += 1 +} diff --git a/src/runtime/race/testdata/comp_test.go b/src/runtime/race/testdata/comp_test.go new file mode 100644 index 0000000..27b2d00 --- /dev/null +++ b/src/runtime/race/testdata/comp_test.go @@ -0,0 +1,186 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "testing" +) + +type P struct { + x, y int +} + +type S struct { + s1, s2 P +} + +func TestNoRaceComp(t *testing.T) { + c := make(chan bool, 1) + var s S + go func() { + s.s2.x = 1 + c <- true + }() + s.s2.y = 2 + <-c +} + +func TestNoRaceComp2(t *testing.T) { + c := make(chan bool, 1) + var s S + go func() { + s.s1.x = 1 + c <- true + }() + s.s1.y = 2 + <-c +} + +func TestRaceComp(t *testing.T) { + c := make(chan bool, 1) + var s S + go func() { + s.s2.y = 1 + c <- true + }() + s.s2.y = 2 + <-c +} + +func TestRaceComp2(t *testing.T) { + c := make(chan bool, 1) + var s S + go func() { + s.s1.x = 1 + c <- true + }() + s = S{} + <-c +} + +func TestRaceComp3(t *testing.T) { + c := make(chan bool, 1) + var s S + go func() { + s.s2.y = 1 + c <- true + }() + s = S{} + <-c +} + +func TestRaceCompArray(t *testing.T) { + c := make(chan bool, 1) + s := make([]S, 10) + x := 4 + go func() { + s[x].s2.y = 1 + c <- true + }() + x = 5 + <-c +} + +type P2 P +type S2 S + +func TestRaceConv1(t *testing.T) { + c := make(chan bool, 1) + var p P2 + go func() { + p.x = 1 + c <- true + }() + _ = P(p).x + <-c +} + +func TestRaceConv2(t *testing.T) { + c := make(chan bool, 1) + var p P2 + go func() { + p.x = 1 + c <- true + }() + ptr := &p + _ = P(*ptr).x + <-c +} + +func TestRaceConv3(t *testing.T) { + c := make(chan bool, 1) + var s S2 + go func() { + s.s1.x = 1 + c <- true + }() + _ = P2(S(s).s1).x + <-c +} + +type X struct { + V [4]P +} + +type X2 X + +func TestRaceConv4(t *testing.T) { + c := make(chan bool, 1) + var x X2 + go func() { + x.V[1].x = 1 + c <- true + }() + _ = P2(X(x).V[1]).x + <-c +} + +type Ptr struct { + s1, s2 *P +} + +func TestNoRaceCompPtr(t *testing.T) { + c := make(chan bool, 1) + p := Ptr{&P{}, &P{}} + go func() { + p.s1.x = 1 + c <- true + }() + p.s1.y = 2 + <-c +} + +func TestNoRaceCompPtr2(t *testing.T) { + c := make(chan bool, 1) + p := Ptr{&P{}, &P{}} + go func() { + p.s1.x = 1 + c <- true + }() + _ = p + <-c +} + +func TestRaceCompPtr(t *testing.T) { + c := make(chan bool, 1) + p := Ptr{&P{}, &P{}} + go func() { + p.s2.x = 1 + c <- true + }() + p.s2.x = 2 + <-c +} + +func TestRaceCompPtr2(t *testing.T) { + c := make(chan bool, 1) + p := Ptr{&P{}, &P{}} + go func() { + p.s2.x = 1 + c <- true + }() + p.s2 = &P{} + <-c +} diff --git a/src/runtime/race/testdata/finalizer_test.go b/src/runtime/race/testdata/finalizer_test.go new file mode 100644 index 0000000..3ac33d2 --- /dev/null +++ b/src/runtime/race/testdata/finalizer_test.go @@ -0,0 +1,68 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "runtime" + "sync" + "testing" + "time" +) + +func TestNoRaceFin(t *testing.T) { + c := make(chan bool) + go func() { + x := new(string) + runtime.SetFinalizer(x, func(x *string) { + *x = "foo" + }) + *x = "bar" + c <- true + }() + <-c + runtime.GC() + time.Sleep(100 * time.Millisecond) +} + +var finVar struct { + sync.Mutex + cnt int +} + +func TestNoRaceFinGlobal(t *testing.T) { + c := make(chan bool) + go func() { + x := new(string) + runtime.SetFinalizer(x, func(x *string) { + finVar.Lock() + finVar.cnt++ + finVar.Unlock() + }) + c <- true + }() + <-c + runtime.GC() + time.Sleep(100 * time.Millisecond) + finVar.Lock() + finVar.cnt++ + finVar.Unlock() +} + +func TestRaceFin(t *testing.T) { + c := make(chan bool) + y := 0 + _ = y + go func() { + x := new(string) + runtime.SetFinalizer(x, func(x *string) { + y = 42 + }) + c <- true + }() + <-c + runtime.GC() + time.Sleep(100 * time.Millisecond) + y = 66 +} diff --git a/src/runtime/race/testdata/io_test.go b/src/runtime/race/testdata/io_test.go new file mode 100644 index 0000000..3303cb0 --- /dev/null +++ b/src/runtime/race/testdata/io_test.go @@ -0,0 +1,75 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "fmt" + "net" + "net/http" + "os" + "path/filepath" + "sync" + "testing" + "time" +) + +func TestNoRaceIOFile(t *testing.T) { + x := 0 + path := t.TempDir() + fname := filepath.Join(path, "data") + go func() { + x = 42 + f, _ := os.Create(fname) + f.Write([]byte("done")) + f.Close() + }() + for { + f, err := os.Open(fname) + if err != nil { + time.Sleep(1e6) + continue + } + buf := make([]byte, 100) + count, err := f.Read(buf) + if count == 0 { + time.Sleep(1e6) + continue + } + break + } + _ = x +} + +var ( + regHandler sync.Once + handlerData int +) + +func TestNoRaceIOHttp(t *testing.T) { + regHandler.Do(func() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + handlerData++ + fmt.Fprintf(w, "test") + handlerData++ + }) + }) + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("net.Listen: %v", err) + } + defer ln.Close() + go http.Serve(ln, nil) + handlerData++ + _, err = http.Get("http://" + ln.Addr().String()) + if err != nil { + t.Fatalf("http.Get: %v", err) + } + handlerData++ + _, err = http.Get("http://" + ln.Addr().String()) + if err != nil { + t.Fatalf("http.Get: %v", err) + } + handlerData++ +} diff --git a/src/runtime/race/testdata/issue12225_test.go b/src/runtime/race/testdata/issue12225_test.go new file mode 100644 index 0000000..0494493 --- /dev/null +++ b/src/runtime/race/testdata/issue12225_test.go @@ -0,0 +1,20 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import "unsafe" + +// golang.org/issue/12225 +// The test is that this compiles at all. + +//go:noinline +func convert(s string) []byte { + return []byte(s) +} + +func issue12225() { + println(*(*int)(unsafe.Pointer(&convert("")[0]))) + println(*(*int)(unsafe.Pointer(&[]byte("")[0]))) +} diff --git a/src/runtime/race/testdata/issue12664_test.go b/src/runtime/race/testdata/issue12664_test.go new file mode 100644 index 0000000..714e83d --- /dev/null +++ b/src/runtime/race/testdata/issue12664_test.go @@ -0,0 +1,76 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "fmt" + "testing" +) + +var issue12664 = "hi" + +func TestRaceIssue12664(t *testing.T) { + c := make(chan struct{}) + go func() { + issue12664 = "bye" + close(c) + }() + fmt.Println(issue12664) + <-c +} + +type MyI interface { + foo() +} + +type MyT int + +func (MyT) foo() { +} + +var issue12664_2 MyT = 0 + +func TestRaceIssue12664_2(t *testing.T) { + c := make(chan struct{}) + go func() { + issue12664_2 = 1 + close(c) + }() + func(x MyI) { + // Never true, but prevents inlining. + if x.(MyT) == -1 { + close(c) + } + }(issue12664_2) + <-c +} + +var issue12664_3 MyT = 0 + +func TestRaceIssue12664_3(t *testing.T) { + c := make(chan struct{}) + go func() { + issue12664_3 = 1 + close(c) + }() + var r MyT + var i any = r + issue12664_3 = i.(MyT) + <-c +} + +var issue12664_4 MyT = 0 + +func TestRaceIssue12664_4(t *testing.T) { + c := make(chan struct{}) + go func() { + issue12664_4 = 1 + close(c) + }() + var r MyT + var i MyI = r + issue12664_4 = i.(MyT) + <-c +} diff --git a/src/runtime/race/testdata/issue13264_test.go b/src/runtime/race/testdata/issue13264_test.go new file mode 100644 index 0000000..d42290d --- /dev/null +++ b/src/runtime/race/testdata/issue13264_test.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +// golang.org/issue/13264 +// The test is that this compiles at all. + +func issue13264() { + for ; ; []map[int]int{}[0][0] = 0 { + } +} diff --git a/src/runtime/race/testdata/map_test.go b/src/runtime/race/testdata/map_test.go new file mode 100644 index 0000000..88e735e --- /dev/null +++ b/src/runtime/race/testdata/map_test.go @@ -0,0 +1,335 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "testing" +) + +func TestRaceMapRW(t *testing.T) { + m := make(map[int]int) + ch := make(chan bool, 1) + go func() { + _ = m[1] + ch <- true + }() + m[1] = 1 + <-ch +} + +func TestRaceMapRW2(t *testing.T) { + m := make(map[int]int) + ch := make(chan bool, 1) + go func() { + _, _ = m[1] + ch <- true + }() + m[1] = 1 + <-ch +} + +func TestRaceMapRWArray(t *testing.T) { + // Check instrumentation of unaddressable arrays (issue 4578). + m := make(map[int][2]int) + ch := make(chan bool, 1) + go func() { + _ = m[1][1] + ch <- true + }() + m[2] = [2]int{1, 2} + <-ch +} + +func TestNoRaceMapRR(t *testing.T) { + m := make(map[int]int) + ch := make(chan bool, 1) + go func() { + _, _ = m[1] + ch <- true + }() + _ = m[1] + <-ch +} + +func TestRaceMapRange(t *testing.T) { + m := make(map[int]int) + ch := make(chan bool, 1) + go func() { + for range m { + } + ch <- true + }() + m[1] = 1 + <-ch +} + +func TestRaceMapRange2(t *testing.T) { + m := make(map[int]int) + ch := make(chan bool, 1) + go func() { + for range m { + } + ch <- true + }() + m[1] = 1 + <-ch +} + +func TestNoRaceMapRangeRange(t *testing.T) { + m := make(map[int]int) + // now the map is not empty and range triggers an event + // should work without this (as in other tests) + // so it is suspicious if this test passes and others don't + m[0] = 0 + ch := make(chan bool, 1) + go func() { + for range m { + } + ch <- true + }() + for range m { + } + <-ch +} + +func TestRaceMapLen(t *testing.T) { + m := make(map[string]bool) + ch := make(chan bool, 1) + go func() { + _ = len(m) + ch <- true + }() + m[""] = true + <-ch +} + +func TestRaceMapDelete(t *testing.T) { + m := make(map[string]bool) + ch := make(chan bool, 1) + go func() { + delete(m, "") + ch <- true + }() + m[""] = true + <-ch +} + +func TestRaceMapLenDelete(t *testing.T) { + m := make(map[string]bool) + ch := make(chan bool, 1) + go func() { + delete(m, "a") + ch <- true + }() + _ = len(m) + <-ch +} + +func TestRaceMapVariable(t *testing.T) { + ch := make(chan bool, 1) + m := make(map[int]int) + _ = m + go func() { + m = make(map[int]int) + ch <- true + }() + m = make(map[int]int) + <-ch +} + +func TestRaceMapVariable2(t *testing.T) { + ch := make(chan bool, 1) + m := make(map[int]int) + go func() { + m[1] = 1 + ch <- true + }() + m = make(map[int]int) + <-ch +} + +func TestRaceMapVariable3(t *testing.T) { + ch := make(chan bool, 1) + m := make(map[int]int) + go func() { + _ = m[1] + ch <- true + }() + m = make(map[int]int) + <-ch +} + +type Big struct { + x [17]int32 +} + +func TestRaceMapLookupPartKey(t *testing.T) { + k := &Big{} + m := make(map[Big]bool) + ch := make(chan bool, 1) + go func() { + k.x[8] = 1 + ch <- true + }() + _ = m[*k] + <-ch +} + +func TestRaceMapLookupPartKey2(t *testing.T) { + k := &Big{} + m := make(map[Big]bool) + ch := make(chan bool, 1) + go func() { + k.x[8] = 1 + ch <- true + }() + _, _ = m[*k] + <-ch +} +func TestRaceMapDeletePartKey(t *testing.T) { + k := &Big{} + m := make(map[Big]bool) + ch := make(chan bool, 1) + go func() { + k.x[8] = 1 + ch <- true + }() + delete(m, *k) + <-ch +} + +func TestRaceMapInsertPartKey(t *testing.T) { + k := &Big{} + m := make(map[Big]bool) + ch := make(chan bool, 1) + go func() { + k.x[8] = 1 + ch <- true + }() + m[*k] = true + <-ch +} + +func TestRaceMapInsertPartVal(t *testing.T) { + v := &Big{} + m := make(map[int]Big) + ch := make(chan bool, 1) + go func() { + v.x[8] = 1 + ch <- true + }() + m[1] = *v + <-ch +} + +// Test for issue 7561. +func TestRaceMapAssignMultipleReturn(t *testing.T) { + connect := func() (int, error) { return 42, nil } + conns := make(map[int][]int) + conns[1] = []int{0} + ch := make(chan bool, 1) + var err error + _ = err + go func() { + conns[1][0], err = connect() + ch <- true + }() + x := conns[1][0] + _ = x + <-ch +} + +// BigKey and BigVal must be larger than 256 bytes, +// so that compiler sets KindGCProg for them. +type BigKey [1000]*int + +type BigVal struct { + x int + y [1000]*int +} + +func TestRaceMapBigKeyAccess1(t *testing.T) { + m := make(map[BigKey]int) + var k BigKey + ch := make(chan bool, 1) + go func() { + _ = m[k] + ch <- true + }() + k[30] = new(int) + <-ch +} + +func TestRaceMapBigKeyAccess2(t *testing.T) { + m := make(map[BigKey]int) + var k BigKey + ch := make(chan bool, 1) + go func() { + _, _ = m[k] + ch <- true + }() + k[30] = new(int) + <-ch +} + +func TestRaceMapBigKeyInsert(t *testing.T) { + m := make(map[BigKey]int) + var k BigKey + ch := make(chan bool, 1) + go func() { + m[k] = 1 + ch <- true + }() + k[30] = new(int) + <-ch +} + +func TestRaceMapBigKeyDelete(t *testing.T) { + m := make(map[BigKey]int) + var k BigKey + ch := make(chan bool, 1) + go func() { + delete(m, k) + ch <- true + }() + k[30] = new(int) + <-ch +} + +func TestRaceMapBigValInsert(t *testing.T) { + m := make(map[int]BigVal) + var v BigVal + ch := make(chan bool, 1) + go func() { + m[1] = v + ch <- true + }() + v.y[30] = new(int) + <-ch +} + +func TestRaceMapBigValAccess1(t *testing.T) { + m := make(map[int]BigVal) + var v BigVal + ch := make(chan bool, 1) + go func() { + v = m[1] + ch <- true + }() + v.y[30] = new(int) + <-ch +} + +func TestRaceMapBigValAccess2(t *testing.T) { + m := make(map[int]BigVal) + var v BigVal + ch := make(chan bool, 1) + go func() { + v, _ = m[1] + ch <- true + }() + v.y[30] = new(int) + <-ch +} diff --git a/src/runtime/race/testdata/mop_test.go b/src/runtime/race/testdata/mop_test.go new file mode 100644 index 0000000..0d79091 --- /dev/null +++ b/src/runtime/race/testdata/mop_test.go @@ -0,0 +1,2094 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "bytes" + "errors" + "fmt" + "hash/crc32" + "io" + "os" + "runtime" + "sync" + "testing" + "time" + "unsafe" +) + +type Point struct { + x, y int +} + +type NamedPoint struct { + name string + p Point +} + +type DummyWriter struct { + state int +} +type Writer interface { + Write(p []byte) (n int) +} + +func (d DummyWriter) Write(p []byte) (n int) { + return 0 +} + +var GlobalX, GlobalY int = 0, 0 +var GlobalCh chan int = make(chan int, 2) + +func GlobalFunc1() { + GlobalY = GlobalX + GlobalCh <- 1 +} + +func GlobalFunc2() { + GlobalX = 1 + GlobalCh <- 1 +} + +func TestRaceIntRWGlobalFuncs(t *testing.T) { + go GlobalFunc1() + go GlobalFunc2() + <-GlobalCh + <-GlobalCh +} + +func TestRaceIntRWClosures(t *testing.T) { + var x, y int + _ = y + ch := make(chan int, 2) + + go func() { + y = x + ch <- 1 + }() + go func() { + x = 1 + ch <- 1 + }() + <-ch + <-ch +} + +func TestNoRaceIntRWClosures(t *testing.T) { + var x, y int + _ = y + ch := make(chan int, 1) + + go func() { + y = x + ch <- 1 + }() + <-ch + go func() { + x = 1 + ch <- 1 + }() + <-ch + +} + +func TestRaceInt32RWClosures(t *testing.T) { + var x, y int32 + _ = y + ch := make(chan bool, 2) + + go func() { + y = x + ch <- true + }() + go func() { + x = 1 + ch <- true + }() + <-ch + <-ch +} + +func TestNoRaceCase(t *testing.T) { + var y int + for x := -1; x <= 1; x++ { + switch { + case x < 0: + y = -1 + case x == 0: + y = 0 + case x > 0: + y = 1 + } + } + y++ +} + +func TestRaceCaseCondition(t *testing.T) { + var x int = 0 + ch := make(chan int, 2) + + go func() { + x = 2 + ch <- 1 + }() + go func() { + switch x < 2 { + case true: + x = 1 + //case false: + // x = 5 + } + ch <- 1 + }() + <-ch + <-ch +} + +func TestRaceCaseCondition2(t *testing.T) { + // switch body is rearranged by the compiler so the tests + // passes even if we don't instrument '<' + var x int = 0 + ch := make(chan int, 2) + + go func() { + x = 2 + ch <- 1 + }() + go func() { + switch x < 2 { + case true: + x = 1 + case false: + x = 5 + } + ch <- 1 + }() + <-ch + <-ch +} + +func TestRaceCaseBody(t *testing.T) { + var x, y int + _ = y + ch := make(chan int, 2) + + go func() { + y = x + ch <- 1 + }() + go func() { + switch { + default: + x = 1 + case x == 100: + x = -x + } + ch <- 1 + }() + <-ch + <-ch +} + +func TestNoRaceCaseFallthrough(t *testing.T) { + var x, y, z int + _ = y + ch := make(chan int, 2) + z = 1 + + go func() { + y = x + ch <- 1 + }() + go func() { + switch { + case z == 1: + case z == 2: + x = 2 + } + ch <- 1 + }() + <-ch + <-ch +} + +func TestRaceCaseFallthrough(t *testing.T) { + var x, y, z int + _ = y + ch := make(chan int, 2) + z = 1 + + go func() { + y = x + ch <- 1 + }() + go func() { + switch { + case z == 1: + fallthrough + case z == 2: + x = 2 + } + ch <- 1 + }() + + <-ch + <-ch +} + +func TestRaceCaseIssue6418(t *testing.T) { + m := map[string]map[string]string{ + "a": { + "b": "c", + }, + } + ch := make(chan int) + go func() { + m["a"]["x"] = "y" + ch <- 1 + }() + switch m["a"]["b"] { + } + <-ch +} + +func TestRaceCaseType(t *testing.T) { + var x, y int + var i any = x + c := make(chan int, 1) + go func() { + switch i.(type) { + case nil: + case int: + } + c <- 1 + }() + i = y + <-c +} + +func TestRaceCaseTypeBody(t *testing.T) { + var x, y int + var i any = &x + c := make(chan int, 1) + go func() { + switch i := i.(type) { + case nil: + case *int: + *i = y + } + c <- 1 + }() + x = y + <-c +} + +func TestRaceCaseTypeIssue5890(t *testing.T) { + // spurious extra instrumentation of the initial interface + // value. + var x, y int + m := make(map[int]map[int]any) + m[0] = make(map[int]any) + c := make(chan int, 1) + go func() { + switch i := m[0][1].(type) { + case nil: + case *int: + *i = x + } + c <- 1 + }() + m[0][1] = y + <-c +} + +func TestNoRaceRange(t *testing.T) { + ch := make(chan int, 3) + a := [...]int{1, 2, 3} + for _, v := range a { + ch <- v + } + close(ch) +} + +func TestNoRaceRangeIssue5446(t *testing.T) { + ch := make(chan int, 3) + a := []int{1, 2, 3} + b := []int{4} + // used to insert a spurious instrumentation of a[i] + // and crash. + i := 1 + for i, a[i] = range b { + ch <- i + } + close(ch) +} + +func TestRaceRange(t *testing.T) { + const N = 2 + var a [N]int + var x, y int + _ = x + y + done := make(chan bool, N) + for i, v := range a { + go func(i int) { + // we don't want a write-vs-write race + // so there is no array b here + if i == 0 { + x = v + } else { + y = v + } + done <- true + }(i) + // Ensure the goroutine runs before we continue the loop. + runtime.Gosched() + } + for i := 0; i < N; i++ { + <-done + } +} + +func TestRaceForInit(t *testing.T) { + c := make(chan int) + x := 0 + go func() { + c <- x + }() + for x = 42; false; { + } + <-c +} + +func TestNoRaceForInit(t *testing.T) { + done := make(chan bool) + c := make(chan bool) + x := 0 + go func() { + for { + _, ok := <-c + if !ok { + done <- true + return + } + x++ + } + }() + i := 0 + for x = 42; i < 10; i++ { + c <- true + } + close(c) + <-done +} + +func TestRaceForTest(t *testing.T) { + done := make(chan bool) + c := make(chan bool) + stop := false + go func() { + for { + _, ok := <-c + if !ok { + done <- true + return + } + stop = true + } + }() + for !stop { + c <- true + } + close(c) + <-done +} + +func TestRaceForIncr(t *testing.T) { + done := make(chan bool) + c := make(chan bool) + x := 0 + go func() { + for { + _, ok := <-c + if !ok { + done <- true + return + } + x++ + } + }() + for i := 0; i < 10; x++ { + i++ + c <- true + } + close(c) + <-done +} + +func TestNoRaceForIncr(t *testing.T) { + done := make(chan bool) + x := 0 + go func() { + x++ + done <- true + }() + for i := 0; i < 0; x++ { + } + <-done +} + +func TestRacePlus(t *testing.T) { + var x, y, z int + _ = y + ch := make(chan int, 2) + + go func() { + y = x + z + ch <- 1 + }() + go func() { + y = x + z + z + ch <- 1 + }() + <-ch + <-ch +} + +func TestRacePlus2(t *testing.T) { + var x, y, z int + _ = y + ch := make(chan int, 2) + + go func() { + x = 1 + ch <- 1 + }() + go func() { + y = +x + z + ch <- 1 + }() + <-ch + <-ch +} + +func TestNoRacePlus(t *testing.T) { + var x, y, z, f int + _ = x + y + f + ch := make(chan int, 2) + + go func() { + y = x + z + ch <- 1 + }() + go func() { + f = z + x + ch <- 1 + }() + <-ch + <-ch +} + +func TestRaceComplement(t *testing.T) { + var x, y, z int + _ = x + ch := make(chan int, 2) + + go func() { + x = ^y + ch <- 1 + }() + go func() { + y = ^z + ch <- 1 + }() + <-ch + <-ch +} + +func TestRaceDiv(t *testing.T) { + var x, y, z int + _ = x + ch := make(chan int, 2) + + go func() { + x = y / (z + 1) + ch <- 1 + }() + go func() { + y = z + ch <- 1 + }() + <-ch + <-ch +} + +func TestRaceDivConst(t *testing.T) { + var x, y, z uint32 + _ = x + ch := make(chan int, 2) + + go func() { + x = y / 3 // involves only a HMUL node + ch <- 1 + }() + go func() { + y = z + ch <- 1 + }() + <-ch + <-ch +} + +func TestRaceMod(t *testing.T) { + var x, y, z int + _ = x + ch := make(chan int, 2) + + go func() { + x = y % (z + 1) + ch <- 1 + }() + go func() { + y = z + ch <- 1 + }() + <-ch + <-ch +} + +func TestRaceModConst(t *testing.T) { + var x, y, z int + _ = x + ch := make(chan int, 2) + + go func() { + x = y % 3 + ch <- 1 + }() + go func() { + y = z + ch <- 1 + }() + <-ch + <-ch +} + +func TestRaceRotate(t *testing.T) { + var x, y, z uint32 + _ = x + ch := make(chan int, 2) + + go func() { + x = y<<12 | y>>20 + ch <- 1 + }() + go func() { + y = z + ch <- 1 + }() + <-ch + <-ch +} + +// May crash if the instrumentation is reckless. +func TestNoRaceEnoughRegisters(t *testing.T) { + // from erf.go + const ( + sa1 = 1 + sa2 = 2 + sa3 = 3 + sa4 = 4 + sa5 = 5 + sa6 = 6 + sa7 = 7 + sa8 = 8 + ) + var s, S float64 + s = 3.1415 + S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8))))))) + s = S +} + +// emptyFunc should not be inlined. +func emptyFunc(x int) { + if false { + fmt.Println(x) + } +} + +func TestRaceFuncArgument(t *testing.T) { + var x int + ch := make(chan bool, 1) + go func() { + emptyFunc(x) + ch <- true + }() + x = 1 + <-ch +} + +func TestRaceFuncArgument2(t *testing.T) { + var x int + ch := make(chan bool, 2) + go func() { + x = 42 + ch <- true + }() + go func(y int) { + ch <- true + }(x) + <-ch + <-ch +} + +func TestRaceSprint(t *testing.T) { + var x int + ch := make(chan bool, 1) + go func() { + fmt.Sprint(x) + ch <- true + }() + x = 1 + <-ch +} + +func TestRaceArrayCopy(t *testing.T) { + ch := make(chan bool, 1) + var a [5]int + go func() { + a[3] = 1 + ch <- true + }() + a = [5]int{1, 2, 3, 4, 5} + <-ch +} + +// Blows up a naive compiler. +func TestRaceNestedArrayCopy(t *testing.T) { + ch := make(chan bool, 1) + type ( + Point32 [2][2][2][2][2]Point + Point1024 [2][2][2][2][2]Point32 + Point32k [2][2][2][2][2]Point1024 + Point1M [2][2][2][2][2]Point32k + ) + var a, b Point1M + go func() { + a[0][1][0][1][0][1][0][1][0][1][0][1][0][1][0][1][0][1][0][1].y = 1 + ch <- true + }() + a = b + <-ch +} + +func TestRaceStructRW(t *testing.T) { + p := Point{0, 0} + ch := make(chan bool, 1) + go func() { + p = Point{1, 1} + ch <- true + }() + q := p + <-ch + p = q +} + +func TestRaceStructFieldRW1(t *testing.T) { + p := Point{0, 0} + ch := make(chan bool, 1) + go func() { + p.x = 1 + ch <- true + }() + _ = p.x + <-ch +} + +func TestNoRaceStructFieldRW1(t *testing.T) { + // Same struct, different variables, no + // pointers. The layout is known (at compile time?) -> + // no read on p + // writes on x and y + p := Point{0, 0} + ch := make(chan bool, 1) + go func() { + p.x = 1 + ch <- true + }() + p.y = 1 + <-ch + _ = p +} + +func TestNoRaceStructFieldRW2(t *testing.T) { + // Same as NoRaceStructFieldRW1 + // but p is a pointer, so there is a read on p + p := Point{0, 0} + ch := make(chan bool, 1) + go func() { + p.x = 1 + ch <- true + }() + p.y = 1 + <-ch + _ = p +} + +func TestRaceStructFieldRW2(t *testing.T) { + p := &Point{0, 0} + ch := make(chan bool, 1) + go func() { + p.x = 1 + ch <- true + }() + _ = p.x + <-ch +} + +func TestRaceStructFieldRW3(t *testing.T) { + p := NamedPoint{name: "a", p: Point{0, 0}} + ch := make(chan bool, 1) + go func() { + p.p.x = 1 + ch <- true + }() + _ = p.p.x + <-ch +} + +func TestRaceEfaceWW(t *testing.T) { + var a, b any + ch := make(chan bool, 1) + go func() { + a = 1 + ch <- true + }() + a = 2 + <-ch + _, _ = a, b +} + +func TestRaceIfaceWW(t *testing.T) { + var a, b Writer + ch := make(chan bool, 1) + go func() { + a = DummyWriter{1} + ch <- true + }() + a = DummyWriter{2} + <-ch + b = a + a = b +} + +func TestRaceIfaceCmp(t *testing.T) { + var a, b Writer + a = DummyWriter{1} + ch := make(chan bool, 1) + go func() { + a = DummyWriter{1} + ch <- true + }() + _ = a == b + <-ch +} + +func TestRaceIfaceCmpNil(t *testing.T) { + var a Writer + a = DummyWriter{1} + ch := make(chan bool, 1) + go func() { + a = DummyWriter{1} + ch <- true + }() + _ = a == nil + <-ch +} + +func TestRaceEfaceConv(t *testing.T) { + c := make(chan bool) + v := 0 + go func() { + go func(x any) { + }(v) + c <- true + }() + v = 42 + <-c +} + +type OsFile struct{} + +func (*OsFile) Read() { +} + +type IoReader interface { + Read() +} + +func TestRaceIfaceConv(t *testing.T) { + c := make(chan bool) + f := &OsFile{} + go func() { + go func(x IoReader) { + }(f) + c <- true + }() + f = &OsFile{} + <-c +} + +func TestRaceError(t *testing.T) { + ch := make(chan bool, 1) + var err error + go func() { + err = nil + ch <- true + }() + _ = err + <-ch +} + +func TestRaceIntptrRW(t *testing.T) { + var x, y int + var p *int = &x + ch := make(chan bool, 1) + go func() { + *p = 5 + ch <- true + }() + y = *p + x = y + <-ch +} + +func TestRaceStringRW(t *testing.T) { + ch := make(chan bool, 1) + s := "" + go func() { + s = "abacaba" + ch <- true + }() + _ = s + <-ch +} + +func TestRaceStringPtrRW(t *testing.T) { + ch := make(chan bool, 1) + var x string + p := &x + go func() { + *p = "a" + ch <- true + }() + _ = *p + <-ch +} + +func TestRaceFloat64WW(t *testing.T) { + var x, y float64 + ch := make(chan bool, 1) + go func() { + x = 1.0 + ch <- true + }() + x = 2.0 + <-ch + + y = x + x = y +} + +func TestRaceComplex128WW(t *testing.T) { + var x, y complex128 + ch := make(chan bool, 1) + go func() { + x = 2 + 2i + ch <- true + }() + x = 4 + 4i + <-ch + + y = x + x = y +} + +func TestRaceUnsafePtrRW(t *testing.T) { + var x, y, z int + x, y, z = 1, 2, 3 + var p unsafe.Pointer = unsafe.Pointer(&x) + ch := make(chan bool, 1) + go func() { + p = (unsafe.Pointer)(&z) + ch <- true + }() + y = *(*int)(p) + x = y + <-ch +} + +func TestRaceFuncVariableRW(t *testing.T) { + var f func(x int) int + f = func(x int) int { + return x * x + } + ch := make(chan bool, 1) + go func() { + f = func(x int) int { + return x + } + ch <- true + }() + y := f(1) + <-ch + x := y + y = x +} + +func TestRaceFuncVariableWW(t *testing.T) { + var f func(x int) int + _ = f + ch := make(chan bool, 1) + go func() { + f = func(x int) int { + return x + } + ch <- true + }() + f = func(x int) int { + return x * x + } + <-ch +} + +// This one should not belong to mop_test +func TestRacePanic(t *testing.T) { + var x int + _ = x + var zero int = 0 + ch := make(chan bool, 2) + go func() { + defer func() { + err := recover() + if err == nil { + panic("should be panicking") + } + x = 1 + ch <- true + }() + var y int = 1 / zero + zero = y + }() + go func() { + defer func() { + err := recover() + if err == nil { + panic("should be panicking") + } + x = 2 + ch <- true + }() + var y int = 1 / zero + zero = y + }() + + <-ch + <-ch + if zero != 0 { + panic("zero has changed") + } +} + +func TestNoRaceBlank(t *testing.T) { + var a [5]int + ch := make(chan bool, 1) + go func() { + _, _ = a[0], a[1] + ch <- true + }() + _, _ = a[2], a[3] + <-ch + a[1] = a[0] +} + +func TestRaceAppendRW(t *testing.T) { + a := make([]int, 10) + ch := make(chan bool) + go func() { + _ = append(a, 1) + ch <- true + }() + a[0] = 1 + <-ch +} + +func TestRaceAppendLenRW(t *testing.T) { + a := make([]int, 0) + ch := make(chan bool) + go func() { + a = append(a, 1) + ch <- true + }() + _ = len(a) + <-ch +} + +func TestRaceAppendCapRW(t *testing.T) { + a := make([]int, 0) + ch := make(chan string) + go func() { + a = append(a, 1) + ch <- "" + }() + _ = cap(a) + <-ch +} + +func TestNoRaceFuncArgsRW(t *testing.T) { + ch := make(chan byte, 1) + var x byte + go func(y byte) { + _ = y + ch <- 0 + }(x) + x = 1 + <-ch +} + +func TestRaceFuncArgsRW(t *testing.T) { + ch := make(chan byte, 1) + var x byte + go func(y *byte) { + _ = *y + ch <- 0 + }(&x) + x = 1 + <-ch +} + +// from the mailing list, slightly modified +// unprotected concurrent access to seen[] +func TestRaceCrawl(t *testing.T) { + url := "dummyurl" + depth := 3 + seen := make(map[string]bool) + ch := make(chan int, 100) + var wg sync.WaitGroup + var crawl func(string, int) + crawl = func(u string, d int) { + nurl := 0 + defer func() { + ch <- nurl + }() + seen[u] = true + if d <= 0 { + wg.Done() + return + } + urls := [...]string{"a", "b", "c"} + for _, uu := range urls { + if _, ok := seen[uu]; !ok { + wg.Add(1) + go crawl(uu, d-1) + nurl++ + } + } + wg.Done() + } + wg.Add(1) + go crawl(url, depth) + wg.Wait() +} + +func TestRaceIndirection(t *testing.T) { + ch := make(chan struct{}, 1) + var y int + var x *int = &y + go func() { + *x = 1 + ch <- struct{}{} + }() + *x = 2 + <-ch + _ = *x +} + +func TestRaceRune(t *testing.T) { + c := make(chan bool) + var x rune + go func() { + x = 1 + c <- true + }() + _ = x + <-c +} + +func TestRaceEmptyInterface1(t *testing.T) { + c := make(chan bool) + var x any + go func() { + x = nil + c <- true + }() + _ = x + <-c +} + +func TestRaceEmptyInterface2(t *testing.T) { + c := make(chan bool) + var x any + go func() { + x = &Point{} + c <- true + }() + _ = x + <-c +} + +func TestRaceTLS(t *testing.T) { + comm := make(chan *int) + done := make(chan bool, 2) + go func() { + var x int + comm <- &x + x = 1 + x = *(<-comm) + done <- true + }() + go func() { + p := <-comm + *p = 2 + comm <- p + done <- true + }() + <-done + <-done +} + +func TestNoRaceHeapReallocation(t *testing.T) { + // It is possible that a future implementation + // of memory allocation will ruin this test. + // Increasing n might help in this case, so + // this test is a bit more generic than most of the + // others. + const n = 2 + done := make(chan bool, n) + empty := func(p *int) {} + for i := 0; i < n; i++ { + ms := i + go func() { + <-time.After(time.Duration(ms) * time.Millisecond) + runtime.GC() + var x int + empty(&x) // x goes to the heap + done <- true + }() + } + for i := 0; i < n; i++ { + <-done + } +} + +func TestRaceAnd(t *testing.T) { + c := make(chan bool) + x, y := 0, 0 + go func() { + x = 1 + c <- true + }() + if x == 1 && y == 1 { + } + <-c +} + +func TestRaceAnd2(t *testing.T) { + c := make(chan bool) + x, y := 0, 0 + go func() { + x = 1 + c <- true + }() + if y == 0 && x == 1 { + } + <-c +} + +func TestNoRaceAnd(t *testing.T) { + c := make(chan bool) + x, y := 0, 0 + go func() { + x = 1 + c <- true + }() + if y == 1 && x == 1 { + } + <-c +} + +func TestRaceOr(t *testing.T) { + c := make(chan bool) + x, y := 0, 0 + go func() { + x = 1 + c <- true + }() + if x == 1 || y == 1 { + } + <-c +} + +func TestRaceOr2(t *testing.T) { + c := make(chan bool) + x, y := 0, 0 + go func() { + x = 1 + c <- true + }() + if y == 1 || x == 1 { + } + <-c +} + +func TestNoRaceOr(t *testing.T) { + c := make(chan bool) + x, y := 0, 0 + go func() { + x = 1 + c <- true + }() + if y == 0 || x == 1 { + } + <-c +} + +func TestNoRaceShortCalc(t *testing.T) { + c := make(chan bool) + x, y := 0, 0 + go func() { + y = 1 + c <- true + }() + if x == 0 || y == 0 { + } + <-c +} + +func TestNoRaceShortCalc2(t *testing.T) { + c := make(chan bool) + x, y := 0, 0 + go func() { + y = 1 + c <- true + }() + if x == 1 && y == 0 { + } + <-c +} + +func TestRaceFuncItself(t *testing.T) { + c := make(chan bool) + f := func() {} + go func() { + f() + c <- true + }() + f = func() {} + <-c +} + +func TestNoRaceFuncUnlock(t *testing.T) { + ch := make(chan bool, 1) + var mu sync.Mutex + x := 0 + _ = x + go func() { + mu.Lock() + x = 42 + mu.Unlock() + ch <- true + }() + x = func(mu *sync.Mutex) int { + mu.Lock() + return 43 + }(&mu) + mu.Unlock() + <-ch +} + +func TestRaceStructInit(t *testing.T) { + type X struct { + x, y int + } + c := make(chan bool, 1) + y := 0 + go func() { + y = 42 + c <- true + }() + x := X{x: y} + _ = x + <-c +} + +func TestRaceArrayInit(t *testing.T) { + c := make(chan bool, 1) + y := 0 + go func() { + y = 42 + c <- true + }() + x := []int{0, y, 42} + _ = x + <-c +} + +func TestRaceMapInit(t *testing.T) { + c := make(chan bool, 1) + y := 0 + go func() { + y = 42 + c <- true + }() + x := map[int]int{0: 42, y: 42} + _ = x + <-c +} + +func TestRaceMapInit2(t *testing.T) { + c := make(chan bool, 1) + y := 0 + go func() { + y = 42 + c <- true + }() + x := map[int]int{0: 42, 42: y} + _ = x + <-c +} + +type Inter interface { + Foo(x int) +} +type InterImpl struct { + x, y int +} + +//go:noinline +func (p InterImpl) Foo(x int) { +} + +type InterImpl2 InterImpl + +func (p *InterImpl2) Foo(x int) { + if p == nil { + InterImpl{}.Foo(x) + } + InterImpl(*p).Foo(x) +} + +func TestRaceInterCall(t *testing.T) { + c := make(chan bool, 1) + p := InterImpl{} + var x Inter = p + go func() { + p2 := InterImpl{} + x = p2 + c <- true + }() + x.Foo(0) + <-c +} + +func TestRaceInterCall2(t *testing.T) { + c := make(chan bool, 1) + p := InterImpl{} + var x Inter = p + z := 0 + go func() { + z = 42 + c <- true + }() + x.Foo(z) + <-c +} + +func TestRaceFuncCall(t *testing.T) { + c := make(chan bool, 1) + f := func(x, y int) {} + x, y := 0, 0 + go func() { + y = 42 + c <- true + }() + f(x, y) + <-c +} + +func TestRaceMethodCall(t *testing.T) { + c := make(chan bool, 1) + i := InterImpl{} + x := 0 + go func() { + x = 42 + c <- true + }() + i.Foo(x) + <-c +} + +func TestRaceMethodCall2(t *testing.T) { + c := make(chan bool, 1) + i := &InterImpl{} + go func() { + i = &InterImpl{} + c <- true + }() + i.Foo(0) + <-c +} + +// Method value with concrete value receiver. +func TestRaceMethodValue(t *testing.T) { + c := make(chan bool, 1) + i := InterImpl{} + go func() { + i = InterImpl{} + c <- true + }() + _ = i.Foo + <-c +} + +// Method value with interface receiver. +func TestRaceMethodValue2(t *testing.T) { + c := make(chan bool, 1) + var i Inter = InterImpl{} + go func() { + i = InterImpl{} + c <- true + }() + _ = i.Foo + <-c +} + +// Method value with implicit dereference. +func TestRaceMethodValue3(t *testing.T) { + c := make(chan bool, 1) + i := &InterImpl{} + go func() { + *i = InterImpl{} + c <- true + }() + _ = i.Foo // dereferences i. + <-c +} + +// Method value implicitly taking receiver address. +func TestNoRaceMethodValue(t *testing.T) { + c := make(chan bool, 1) + i := InterImpl2{} + go func() { + i = InterImpl2{} + c <- true + }() + _ = i.Foo // takes the address of i only. + <-c +} + +func TestRacePanicArg(t *testing.T) { + c := make(chan bool, 1) + err := errors.New("err") + go func() { + err = errors.New("err2") + c <- true + }() + defer func() { + recover() + <-c + }() + panic(err) +} + +func TestRaceDeferArg(t *testing.T) { + c := make(chan bool, 1) + x := 0 + go func() { + x = 42 + c <- true + }() + func() { + defer func(x int) { + }(x) + }() + <-c +} + +type DeferT int + +func (d DeferT) Foo() { +} + +func TestRaceDeferArg2(t *testing.T) { + c := make(chan bool, 1) + var x DeferT + go func() { + var y DeferT + x = y + c <- true + }() + func() { + defer x.Foo() + }() + <-c +} + +func TestNoRaceAddrExpr(t *testing.T) { + c := make(chan bool, 1) + x := 0 + go func() { + x = 42 + c <- true + }() + _ = &x + <-c +} + +type AddrT struct { + _ [256]byte + x int +} + +type AddrT2 struct { + _ [512]byte + p *AddrT +} + +func TestRaceAddrExpr(t *testing.T) { + c := make(chan bool, 1) + a := AddrT2{p: &AddrT{x: 42}} + go func() { + a.p = &AddrT{x: 43} + c <- true + }() + _ = &a.p.x + <-c +} + +func TestRaceTypeAssert(t *testing.T) { + c := make(chan bool, 1) + x := 0 + var i any = x + go func() { + y := 0 + i = y + c <- true + }() + _ = i.(int) + <-c +} + +func TestRaceBlockAs(t *testing.T) { + c := make(chan bool, 1) + var x, y int + go func() { + x = 42 + c <- true + }() + x, y = y, x + <-c +} + +func TestRaceBlockCall1(t *testing.T) { + done := make(chan bool) + x, y := 0, 0 + go func() { + f := func() (int, int) { + return 42, 43 + } + x, y = f() + done <- true + }() + _ = x + <-done + if x != 42 || y != 43 { + panic("corrupted data") + } +} +func TestRaceBlockCall2(t *testing.T) { + done := make(chan bool) + x, y := 0, 0 + go func() { + f := func() (int, int) { + return 42, 43 + } + x, y = f() + done <- true + }() + _ = y + <-done + if x != 42 || y != 43 { + panic("corrupted data") + } +} +func TestRaceBlockCall3(t *testing.T) { + done := make(chan bool) + var x *int + y := 0 + go func() { + f := func() (*int, int) { + i := 42 + return &i, 43 + } + x, y = f() + done <- true + }() + _ = x + <-done + if *x != 42 || y != 43 { + panic("corrupted data") + } +} +func TestRaceBlockCall4(t *testing.T) { + done := make(chan bool) + x := 0 + var y *int + go func() { + f := func() (int, *int) { + i := 43 + return 42, &i + } + x, y = f() + done <- true + }() + _ = y + <-done + if x != 42 || *y != 43 { + panic("corrupted data") + } +} +func TestRaceBlockCall5(t *testing.T) { + done := make(chan bool) + var x *int + y := 0 + go func() { + f := func() (*int, int) { + i := 42 + return &i, 43 + } + x, y = f() + done <- true + }() + _ = y + <-done + if *x != 42 || y != 43 { + panic("corrupted data") + } +} +func TestRaceBlockCall6(t *testing.T) { + done := make(chan bool) + x := 0 + var y *int + go func() { + f := func() (int, *int) { + i := 43 + return 42, &i + } + x, y = f() + done <- true + }() + _ = x + <-done + if x != 42 || *y != 43 { + panic("corrupted data") + } +} +func TestRaceSliceSlice(t *testing.T) { + c := make(chan bool, 1) + x := make([]int, 10) + go func() { + x = make([]int, 20) + c <- true + }() + _ = x[2:3] + <-c +} + +func TestRaceSliceSlice2(t *testing.T) { + c := make(chan bool, 1) + x := make([]int, 10) + i := 2 + go func() { + i = 3 + c <- true + }() + _ = x[i:4] + <-c +} + +func TestRaceSliceString(t *testing.T) { + c := make(chan bool, 1) + x := "hello" + go func() { + x = "world" + c <- true + }() + _ = x[2:3] + <-c +} + +func TestRaceSliceStruct(t *testing.T) { + type X struct { + x, y int + } + c := make(chan bool, 1) + x := make([]X, 10) + go func() { + y := make([]X, 10) + copy(y, x) + c <- true + }() + x[1].y = 42 + <-c +} + +func TestRaceAppendSliceStruct(t *testing.T) { + type X struct { + x, y int + } + c := make(chan bool, 1) + x := make([]X, 10) + go func() { + y := make([]X, 0, 10) + y = append(y, x...) + c <- true + }() + x[1].y = 42 + <-c +} + +func TestRaceStructInd(t *testing.T) { + c := make(chan bool, 1) + type Item struct { + x, y int + } + i := Item{} + go func(p *Item) { + *p = Item{} + c <- true + }(&i) + i.y = 42 + <-c +} + +func TestRaceAsFunc1(t *testing.T) { + var s []byte + c := make(chan bool, 1) + go func() { + var err error + s, err = func() ([]byte, error) { + t := []byte("hello world") + return t, nil + }() + c <- true + _ = err + }() + _ = string(s) + <-c +} + +func TestRaceAsFunc2(t *testing.T) { + c := make(chan bool, 1) + x := 0 + go func() { + func(x int) { + }(x) + c <- true + }() + x = 42 + <-c +} + +func TestRaceAsFunc3(t *testing.T) { + c := make(chan bool, 1) + var mu sync.Mutex + x := 0 + go func() { + func(x int) { + mu.Lock() + }(x) // Read of x must be outside of the mutex. + mu.Unlock() + c <- true + }() + mu.Lock() + x = 42 + mu.Unlock() + <-c +} + +func TestNoRaceAsFunc4(t *testing.T) { + c := make(chan bool, 1) + var mu sync.Mutex + x := 0 + _ = x + go func() { + x = func() int { // Write of x must be under the mutex. + mu.Lock() + return 42 + }() + mu.Unlock() + c <- true + }() + mu.Lock() + x = 42 + mu.Unlock() + <-c +} + +func TestRaceHeapParam(t *testing.T) { + done := make(chan bool) + x := func() (x int) { + go func() { + x = 42 + done <- true + }() + return + }() + _ = x + <-done +} + +func TestNoRaceEmptyStruct(t *testing.T) { + type Empty struct{} + type X struct { + y int64 + Empty + } + type Y struct { + x X + y int64 + } + c := make(chan X) + var y Y + go func() { + x := y.x + c <- x + }() + y.y = 42 + <-c +} + +func TestRaceNestedStruct(t *testing.T) { + type X struct { + x, y int + } + type Y struct { + x X + } + c := make(chan Y) + var y Y + go func() { + c <- y + }() + y.x.y = 42 + <-c +} + +func TestRaceIssue5567(t *testing.T) { + testRaceRead(t, false) +} + +func TestRaceIssue51618(t *testing.T) { + testRaceRead(t, true) +} + +func testRaceRead(t *testing.T, pread bool) { + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) + in := make(chan []byte) + res := make(chan error) + go func() { + var err error + defer func() { + close(in) + res <- err + }() + path := "mop_test.go" + f, err := os.Open(path) + if err != nil { + return + } + defer f.Close() + var n, total int + b := make([]byte, 17) // the race is on b buffer + for err == nil { + if pread { + n, err = f.ReadAt(b, int64(total)) + } else { + n, err = f.Read(b) + } + total += n + if n > 0 { + in <- b[:n] + } + } + if err == io.EOF { + err = nil + } + }() + h := crc32.New(crc32.MakeTable(0x12345678)) + for b := range in { + h.Write(b) + } + _ = h.Sum(nil) + err := <-res + if err != nil { + t.Fatal(err) + } +} + +func TestRaceIssue5654(t *testing.T) { + text := `Friends, Romans, countrymen, lend me your ears; +I come to bury Caesar, not to praise him. +The evil that men do lives after them; +The good is oft interred with their bones; +So let it be with Caesar. The noble Brutus +Hath told you Caesar was ambitious: +If it were so, it was a grievous fault, +And grievously hath Caesar answer'd it. +Here, under leave of Brutus and the rest - +For Brutus is an honourable man; +So are they all, all honourable men - +Come I to speak in Caesar's funeral. +He was my friend, faithful and just to me: +But Brutus says he was ambitious; +And Brutus is an honourable man.` + + data := bytes.NewBufferString(text) + in := make(chan []byte) + + go func() { + buf := make([]byte, 16) + var n int + var err error + for ; err == nil; n, err = data.Read(buf) { + in <- buf[:n] + } + close(in) + }() + res := "" + for s := range in { + res += string(s) + } + _ = res +} + +type Base int + +func (b *Base) Foo() int { + return 42 +} + +func (b Base) Bar() int { + return int(b) +} + +func TestNoRaceMethodThunk(t *testing.T) { + type Derived struct { + pad int + Base + } + var d Derived + done := make(chan bool) + go func() { + _ = d.Foo() + done <- true + }() + d = Derived{} + <-done +} + +func TestRaceMethodThunk(t *testing.T) { + type Derived struct { + pad int + *Base + } + var d Derived + done := make(chan bool) + go func() { + _ = d.Foo() + done <- true + }() + d = Derived{} + <-done +} + +func TestRaceMethodThunk2(t *testing.T) { + type Derived struct { + pad int + Base + } + var d Derived + done := make(chan bool) + go func() { + _ = d.Bar() + done <- true + }() + d = Derived{} + <-done +} + +func TestRaceMethodThunk3(t *testing.T) { + type Derived struct { + pad int + *Base + } + var d Derived + d.Base = new(Base) + done := make(chan bool) + go func() { + _ = d.Bar() + done <- true + }() + d.Base = new(Base) + <-done +} + +func TestRaceMethodThunk4(t *testing.T) { + type Derived struct { + pad int + *Base + } + var d Derived + d.Base = new(Base) + done := make(chan bool) + go func() { + _ = d.Bar() + done <- true + }() + *(*int)(d.Base) = 42 + <-done +} + +func TestNoRaceTinyAlloc(t *testing.T) { + const P = 4 + const N = 1e6 + var tinySink *byte + _ = tinySink + done := make(chan bool) + for p := 0; p < P; p++ { + go func() { + for i := 0; i < N; i++ { + var b byte + if b != 0 { + tinySink = &b // make it heap allocated + } + b = 42 + } + done <- true + }() + } + for p := 0; p < P; p++ { + <-done + } +} diff --git a/src/runtime/race/testdata/mutex_test.go b/src/runtime/race/testdata/mutex_test.go new file mode 100644 index 0000000..9dbed9a --- /dev/null +++ b/src/runtime/race/testdata/mutex_test.go @@ -0,0 +1,150 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "sync" + "testing" + "time" +) + +func TestNoRaceMutex(t *testing.T) { + var mu sync.Mutex + var x int16 = 0 + _ = x + ch := make(chan bool, 2) + go func() { + mu.Lock() + defer mu.Unlock() + x = 1 + ch <- true + }() + go func() { + mu.Lock() + x = 2 + mu.Unlock() + ch <- true + }() + <-ch + <-ch +} + +func TestRaceMutex(t *testing.T) { + var mu sync.Mutex + var x int16 = 0 + _ = x + ch := make(chan bool, 2) + go func() { + x = 1 + mu.Lock() + defer mu.Unlock() + ch <- true + }() + go func() { + x = 2 + mu.Lock() + mu.Unlock() + ch <- true + }() + <-ch + <-ch +} + +func TestRaceMutex2(t *testing.T) { + var mu1 sync.Mutex + var mu2 sync.Mutex + var x int8 = 0 + _ = x + ch := make(chan bool, 2) + go func() { + mu1.Lock() + defer mu1.Unlock() + x = 1 + ch <- true + }() + go func() { + mu2.Lock() + x = 2 + mu2.Unlock() + ch <- true + }() + <-ch + <-ch +} + +func TestNoRaceMutexPureHappensBefore(t *testing.T) { + var mu sync.Mutex + var x int16 = 0 + _ = x + written := false + ch := make(chan bool, 2) + go func() { + x = 1 + mu.Lock() + written = true + mu.Unlock() + ch <- true + }() + go func() { + time.Sleep(100 * time.Microsecond) + mu.Lock() + for !written { + mu.Unlock() + time.Sleep(100 * time.Microsecond) + mu.Lock() + } + mu.Unlock() + x = 1 + ch <- true + }() + <-ch + <-ch +} + +func TestNoRaceMutexSemaphore(t *testing.T) { + var mu sync.Mutex + ch := make(chan bool, 2) + x := 0 + _ = x + mu.Lock() + go func() { + x = 1 + mu.Unlock() + ch <- true + }() + go func() { + mu.Lock() + x = 2 + mu.Unlock() + ch <- true + }() + <-ch + <-ch +} + +// from doc/go_mem.html +func TestNoRaceMutexExampleFromHtml(t *testing.T) { + var l sync.Mutex + a := "" + + l.Lock() + go func() { + a = "hello, world" + l.Unlock() + }() + l.Lock() + _ = a +} + +func TestRaceMutexOverwrite(t *testing.T) { + c := make(chan bool, 1) + var mu sync.Mutex + go func() { + mu = sync.Mutex{} + c <- true + }() + mu.Lock() + <-c +} diff --git a/src/runtime/race/testdata/pool_test.go b/src/runtime/race/testdata/pool_test.go new file mode 100644 index 0000000..a96913e --- /dev/null +++ b/src/runtime/race/testdata/pool_test.go @@ -0,0 +1,47 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "sync" + "testing" + "time" +) + +func TestRacePool(t *testing.T) { + // Pool randomly drops the argument on the floor during Put. + // Repeat so that at least one iteration gets reuse. + for i := 0; i < 10; i++ { + c := make(chan int) + p := &sync.Pool{New: func() any { return make([]byte, 10) }} + x := p.Get().([]byte) + x[0] = 1 + p.Put(x) + go func() { + y := p.Get().([]byte) + y[0] = 2 + c <- 1 + }() + x[0] = 3 + <-c + } +} + +func TestNoRacePool(t *testing.T) { + for i := 0; i < 10; i++ { + p := &sync.Pool{New: func() any { return make([]byte, 10) }} + x := p.Get().([]byte) + x[0] = 1 + p.Put(x) + go func() { + y := p.Get().([]byte) + y[0] = 2 + p.Put(y) + }() + time.Sleep(100 * time.Millisecond) + x = p.Get().([]byte) + x[0] = 3 + } +} diff --git a/src/runtime/race/testdata/reflect_test.go b/src/runtime/race/testdata/reflect_test.go new file mode 100644 index 0000000..b567400 --- /dev/null +++ b/src/runtime/race/testdata/reflect_test.go @@ -0,0 +1,46 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "reflect" + "testing" +) + +func TestRaceReflectRW(t *testing.T) { + ch := make(chan bool, 1) + i := 0 + v := reflect.ValueOf(&i) + go func() { + v.Elem().Set(reflect.ValueOf(1)) + ch <- true + }() + _ = v.Elem().Int() + <-ch +} + +func TestRaceReflectWW(t *testing.T) { + ch := make(chan bool, 1) + i := 0 + v := reflect.ValueOf(&i) + go func() { + v.Elem().Set(reflect.ValueOf(1)) + ch <- true + }() + v.Elem().Set(reflect.ValueOf(2)) + <-ch +} + +func TestRaceReflectCopyWW(t *testing.T) { + ch := make(chan bool, 1) + a := make([]byte, 2) + v := reflect.ValueOf(a) + go func() { + reflect.Copy(v, v) + ch <- true + }() + reflect.Copy(v, v) + <-ch +} diff --git a/src/runtime/race/testdata/regression_test.go b/src/runtime/race/testdata/regression_test.go new file mode 100644 index 0000000..6a7802f --- /dev/null +++ b/src/runtime/race/testdata/regression_test.go @@ -0,0 +1,189 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code patterns that caused problems in the past. + +package race_test + +import ( + "testing" +) + +type LogImpl struct { + x int +} + +func NewLog() (l LogImpl) { + c := make(chan bool) + go func() { + _ = l + c <- true + }() + l = LogImpl{} + <-c + return +} + +var _ LogImpl = NewLog() + +func MakeMap() map[int]int { + return make(map[int]int) +} + +func InstrumentMapLen() { + _ = len(MakeMap()) +} + +func InstrumentMapLen2() { + m := make(map[int]map[int]int) + _ = len(m[0]) +} + +func InstrumentMapLen3() { + m := make(map[int]*map[int]int) + _ = len(*m[0]) +} + +func TestRaceUnaddressableMapLen(t *testing.T) { + m := make(map[int]map[int]int) + ch := make(chan int, 1) + m[0] = make(map[int]int) + go func() { + _ = len(m[0]) + ch <- 0 + }() + m[0][0] = 1 + <-ch +} + +type Rect struct { + x, y int +} + +type Image struct { + min, max Rect +} + +//go:noinline +func NewImage() Image { + return Image{} +} + +func AddrOfTemp() { + _ = NewImage().min +} + +type TypeID int + +func (t *TypeID) encodeType(x int) (tt TypeID, err error) { + switch x { + case 0: + return t.encodeType(x * x) + } + return 0, nil +} + +type stack []int + +func (s *stack) push(x int) { + *s = append(*s, x) +} + +func (s *stack) pop() int { + i := len(*s) + n := (*s)[i-1] + *s = (*s)[:i-1] + return n +} + +func TestNoRaceStackPushPop(t *testing.T) { + var s stack + go func(s *stack) {}(&s) + s.push(1) + x := s.pop() + _ = x +} + +type RpcChan struct { + c chan bool +} + +var makeChanCalls int + +//go:noinline +func makeChan() *RpcChan { + makeChanCalls++ + c := &RpcChan{make(chan bool, 1)} + c.c <- true + return c +} + +func call() bool { + x := <-makeChan().c + return x +} + +func TestNoRaceRpcChan(t *testing.T) { + makeChanCalls = 0 + _ = call() + if makeChanCalls != 1 { + t.Fatalf("makeChanCalls %d, expected 1\n", makeChanCalls) + } +} + +func divInSlice() { + v := make([]int64, 10) + i := 1 + _ = v[(i*4)/3] +} + +func TestNoRaceReturn(t *testing.T) { + c := make(chan int) + noRaceReturn(c) + <-c +} + +// Return used to do an implicit a = a, causing a read/write race +// with the goroutine. Compiler has an optimization to avoid that now. +// See issue 4014. +func noRaceReturn(c chan int) (a, b int) { + a = 42 + go func() { + _ = a + c <- 1 + }() + return a, 10 +} + +func issue5431() { + var p **inltype + if inlinetest(p).x && inlinetest(p).y { + } else if inlinetest(p).x || inlinetest(p).y { + } +} + +type inltype struct { + x, y bool +} + +func inlinetest(p **inltype) *inltype { + return *p +} + +type iface interface { + Foo() *struct{ b bool } +} + +type Int int + +func (i Int) Foo() *struct{ b bool } { + return &struct{ b bool }{false} +} + +func TestNoRaceForInfiniteLoop(t *testing.T) { + var x Int + // interface conversion causes nodes to be put on init list + for iface(x).Foo().b { + } +} diff --git a/src/runtime/race/testdata/rwmutex_test.go b/src/runtime/race/testdata/rwmutex_test.go new file mode 100644 index 0000000..39219e5 --- /dev/null +++ b/src/runtime/race/testdata/rwmutex_test.go @@ -0,0 +1,154 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "sync" + "testing" + "time" +) + +func TestRaceMutexRWMutex(t *testing.T) { + var mu1 sync.Mutex + var mu2 sync.RWMutex + var x int16 = 0 + _ = x + ch := make(chan bool, 2) + go func() { + mu1.Lock() + defer mu1.Unlock() + x = 1 + ch <- true + }() + go func() { + mu2.Lock() + x = 2 + mu2.Unlock() + ch <- true + }() + <-ch + <-ch +} + +func TestNoRaceRWMutex(t *testing.T) { + var mu sync.RWMutex + var x, y int64 = 0, 1 + _ = y + ch := make(chan bool, 2) + go func() { + mu.Lock() + defer mu.Unlock() + x = 2 + ch <- true + }() + go func() { + mu.RLock() + y = x + mu.RUnlock() + ch <- true + }() + <-ch + <-ch +} + +func TestRaceRWMutexMultipleReaders(t *testing.T) { + var mu sync.RWMutex + var x, y int64 = 0, 1 + ch := make(chan bool, 4) + go func() { + mu.Lock() + defer mu.Unlock() + x = 2 + ch <- true + }() + // Use three readers so that no matter what order they're + // scheduled in, two will be on the same side of the write + // lock above. + go func() { + mu.RLock() + y = x + 1 + mu.RUnlock() + ch <- true + }() + go func() { + mu.RLock() + y = x + 2 + mu.RUnlock() + ch <- true + }() + go func() { + mu.RLock() + y = x + 3 + mu.RUnlock() + ch <- true + }() + <-ch + <-ch + <-ch + <-ch + _ = y +} + +func TestNoRaceRWMutexMultipleReaders(t *testing.T) { + var mu sync.RWMutex + x := int64(0) + ch := make(chan bool, 4) + go func() { + mu.Lock() + defer mu.Unlock() + x = 2 + ch <- true + }() + go func() { + mu.RLock() + y := x + 1 + _ = y + mu.RUnlock() + ch <- true + }() + go func() { + mu.RLock() + y := x + 2 + _ = y + mu.RUnlock() + ch <- true + }() + go func() { + mu.RLock() + y := x + 3 + _ = y + mu.RUnlock() + ch <- true + }() + <-ch + <-ch + <-ch + <-ch +} + +func TestNoRaceRWMutexTransitive(t *testing.T) { + var mu sync.RWMutex + x := int64(0) + ch := make(chan bool, 2) + go func() { + mu.RLock() + _ = x + mu.RUnlock() + ch <- true + }() + go func() { + time.Sleep(1e7) + mu.RLock() + _ = x + mu.RUnlock() + ch <- true + }() + time.Sleep(2e7) + mu.Lock() + x = 42 + mu.Unlock() + <-ch + <-ch +} diff --git a/src/runtime/race/testdata/select_test.go b/src/runtime/race/testdata/select_test.go new file mode 100644 index 0000000..9a43f9b --- /dev/null +++ b/src/runtime/race/testdata/select_test.go @@ -0,0 +1,293 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "runtime" + "testing" +) + +func TestNoRaceSelect1(t *testing.T) { + var x int + _ = x + compl := make(chan bool) + c := make(chan bool) + c1 := make(chan bool) + + go func() { + x = 1 + // At least two channels are needed because + // otherwise the compiler optimizes select out. + // See comment in runtime/select.go:^func selectgo. + select { + case c <- true: + case c1 <- true: + } + compl <- true + }() + select { + case <-c: + case c1 <- true: + } + x = 2 + <-compl +} + +func TestNoRaceSelect2(t *testing.T) { + var x int + _ = x + compl := make(chan bool) + c := make(chan bool) + c1 := make(chan bool) + go func() { + select { + case <-c: + case <-c1: + } + x = 1 + compl <- true + }() + x = 2 + close(c) + runtime.Gosched() + <-compl +} + +func TestNoRaceSelect3(t *testing.T) { + var x int + _ = x + compl := make(chan bool) + c := make(chan bool, 10) + c1 := make(chan bool) + go func() { + x = 1 + select { + case c <- true: + case <-c1: + } + compl <- true + }() + <-c + x = 2 + <-compl +} + +func TestNoRaceSelect4(t *testing.T) { + type Task struct { + f func() + done chan bool + } + + queue := make(chan Task) + dummy := make(chan bool) + + go func() { + for { + select { + case t := <-queue: + t.f() + t.done <- true + } + } + }() + + doit := func(f func()) { + done := make(chan bool, 1) + select { + case queue <- Task{f, done}: + case <-dummy: + } + select { + case <-done: + case <-dummy: + } + } + + var x int + doit(func() { + x = 1 + }) + _ = x +} + +func TestNoRaceSelect5(t *testing.T) { + test := func(sel, needSched bool) { + var x int + _ = x + ch := make(chan bool) + c1 := make(chan bool) + + done := make(chan bool, 2) + go func() { + if needSched { + runtime.Gosched() + } + // println(1) + x = 1 + if sel { + select { + case ch <- true: + case <-c1: + } + } else { + ch <- true + } + done <- true + }() + + go func() { + // println(2) + if sel { + select { + case <-ch: + case <-c1: + } + } else { + <-ch + } + x = 1 + done <- true + }() + <-done + <-done + } + + test(true, true) + test(true, false) + test(false, true) + test(false, false) +} + +func TestRaceSelect1(t *testing.T) { + var x int + _ = x + compl := make(chan bool, 2) + c := make(chan bool) + c1 := make(chan bool) + + go func() { + <-c + <-c + }() + f := func() { + select { + case c <- true: + case c1 <- true: + } + x = 1 + compl <- true + } + go f() + go f() + <-compl + <-compl +} + +func TestRaceSelect2(t *testing.T) { + var x int + _ = x + compl := make(chan bool) + c := make(chan bool) + c1 := make(chan bool) + go func() { + x = 1 + select { + case <-c: + case <-c1: + } + compl <- true + }() + close(c) + x = 2 + <-compl +} + +func TestRaceSelect3(t *testing.T) { + var x int + _ = x + compl := make(chan bool) + c := make(chan bool) + c1 := make(chan bool) + go func() { + x = 1 + select { + case c <- true: + case c1 <- true: + } + compl <- true + }() + x = 2 + select { + case <-c: + } + <-compl +} + +func TestRaceSelect4(t *testing.T) { + done := make(chan bool, 1) + var x int + go func() { + select { + default: + x = 2 + } + done <- true + }() + _ = x + <-done +} + +// The idea behind this test: +// there are two variables, access to one +// of them is synchronized, access to the other +// is not. +// Select must (unconditionally) choose the non-synchronized variable +// thus causing exactly one race. +// Currently this test doesn't look like it accomplishes +// this goal. +func TestRaceSelect5(t *testing.T) { + done := make(chan bool, 1) + c1 := make(chan bool, 1) + c2 := make(chan bool) + var x, y int + go func() { + select { + case c1 <- true: + x = 1 + case c2 <- true: + y = 1 + } + done <- true + }() + _ = x + _ = y + <-done +} + +// select statements may introduce +// flakiness: whether this test contains +// a race depends on the scheduling +// (some may argue that the code contains +// this race by definition) +/* +func TestFlakyDefault(t *testing.T) { + var x int + c := make(chan bool, 1) + done := make(chan bool, 1) + go func() { + select { + case <-c: + x = 2 + default: + x = 3 + } + done <- true + }() + x = 1 + c <- true + _ = x + <-done +} +*/ diff --git a/src/runtime/race/testdata/slice_test.go b/src/runtime/race/testdata/slice_test.go new file mode 100644 index 0000000..9009a9a --- /dev/null +++ b/src/runtime/race/testdata/slice_test.go @@ -0,0 +1,608 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "sync" + "testing" +) + +func TestRaceSliceRW(t *testing.T) { + ch := make(chan bool, 1) + a := make([]int, 2) + go func() { + a[1] = 1 + ch <- true + }() + _ = a[1] + <-ch +} + +func TestNoRaceSliceRW(t *testing.T) { + ch := make(chan bool, 1) + a := make([]int, 2) + go func() { + a[0] = 1 + ch <- true + }() + _ = a[1] + <-ch +} + +func TestRaceSliceWW(t *testing.T) { + a := make([]int, 10) + ch := make(chan bool, 1) + go func() { + a[1] = 1 + ch <- true + }() + a[1] = 2 + <-ch +} + +func TestNoRaceArrayWW(t *testing.T) { + var a [5]int + ch := make(chan bool, 1) + go func() { + a[0] = 1 + ch <- true + }() + a[1] = 2 + <-ch +} + +func TestRaceArrayWW(t *testing.T) { + var a [5]int + ch := make(chan bool, 1) + go func() { + a[1] = 1 + ch <- true + }() + a[1] = 2 + <-ch +} + +func TestNoRaceSliceWriteLen(t *testing.T) { + ch := make(chan bool, 1) + a := make([]bool, 1) + go func() { + a[0] = true + ch <- true + }() + _ = len(a) + <-ch +} + +func TestNoRaceSliceWriteCap(t *testing.T) { + ch := make(chan bool, 1) + a := make([]uint64, 100) + go func() { + a[50] = 123 + ch <- true + }() + _ = cap(a) + <-ch +} + +func TestRaceSliceCopyRead(t *testing.T) { + ch := make(chan bool, 1) + a := make([]int, 10) + b := make([]int, 10) + go func() { + _ = a[5] + ch <- true + }() + copy(a, b) + <-ch +} + +func TestNoRaceSliceWriteCopy(t *testing.T) { + ch := make(chan bool, 1) + a := make([]int, 10) + b := make([]int, 10) + go func() { + a[5] = 1 + ch <- true + }() + copy(a[:5], b[:5]) + <-ch +} + +func TestRaceSliceCopyWrite2(t *testing.T) { + ch := make(chan bool, 1) + a := make([]int, 10) + b := make([]int, 10) + go func() { + b[5] = 1 + ch <- true + }() + copy(a, b) + <-ch +} + +func TestRaceSliceCopyWrite3(t *testing.T) { + ch := make(chan bool, 1) + a := make([]byte, 10) + go func() { + a[7] = 1 + ch <- true + }() + copy(a, "qwertyqwerty") + <-ch +} + +func TestNoRaceSliceCopyRead(t *testing.T) { + ch := make(chan bool, 1) + a := make([]int, 10) + b := make([]int, 10) + go func() { + _ = b[5] + ch <- true + }() + copy(a, b) + <-ch +} + +func TestRacePointerSliceCopyRead(t *testing.T) { + ch := make(chan bool, 1) + a := make([]*int, 10) + b := make([]*int, 10) + go func() { + _ = a[5] + ch <- true + }() + copy(a, b) + <-ch +} + +func TestNoRacePointerSliceWriteCopy(t *testing.T) { + ch := make(chan bool, 1) + a := make([]*int, 10) + b := make([]*int, 10) + go func() { + a[5] = new(int) + ch <- true + }() + copy(a[:5], b[:5]) + <-ch +} + +func TestRacePointerSliceCopyWrite2(t *testing.T) { + ch := make(chan bool, 1) + a := make([]*int, 10) + b := make([]*int, 10) + go func() { + b[5] = new(int) + ch <- true + }() + copy(a, b) + <-ch +} + +func TestNoRacePointerSliceCopyRead(t *testing.T) { + ch := make(chan bool, 1) + a := make([]*int, 10) + b := make([]*int, 10) + go func() { + _ = b[5] + ch <- true + }() + copy(a, b) + <-ch +} + +func TestNoRaceSliceWriteSlice2(t *testing.T) { + ch := make(chan bool, 1) + a := make([]float64, 10) + go func() { + a[2] = 1.0 + ch <- true + }() + _ = a[0:5] + <-ch +} + +func TestRaceSliceWriteSlice(t *testing.T) { + ch := make(chan bool, 1) + a := make([]float64, 10) + go func() { + a[2] = 1.0 + ch <- true + }() + a = a[5:10] + <-ch +} + +func TestNoRaceSliceWriteSlice(t *testing.T) { + ch := make(chan bool, 1) + a := make([]float64, 10) + go func() { + a[2] = 1.0 + ch <- true + }() + _ = a[5:10] + <-ch +} + +func TestNoRaceSliceLenCap(t *testing.T) { + ch := make(chan bool, 1) + a := make([]struct{}, 10) + go func() { + _ = len(a) + ch <- true + }() + _ = cap(a) + <-ch +} + +func TestNoRaceStructSlicesRangeWrite(t *testing.T) { + type Str struct { + a []int + b []int + } + ch := make(chan bool, 1) + var s Str + s.a = make([]int, 10) + s.b = make([]int, 10) + go func() { + for range s.a { + } + ch <- true + }() + s.b[5] = 5 + <-ch +} + +func TestRaceSliceDifferent(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + s2 := s + go func() { + s[3] = 3 + c <- true + }() + // false negative because s2 is PAUTO w/o PHEAP + // so we do not instrument it + s2[3] = 3 + <-c +} + +func TestRaceSliceRangeWrite(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + s[3] = 3 + c <- true + }() + for _, v := range s { + _ = v + } + <-c +} + +func TestNoRaceSliceRangeWrite(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + s[3] = 3 + c <- true + }() + for range s { + } + <-c +} + +func TestRaceSliceRangeAppend(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + s = append(s, 3) + c <- true + }() + for range s { + } + <-c +} + +func TestNoRaceSliceRangeAppend(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + _ = append(s, 3) + c <- true + }() + for range s { + } + <-c +} + +func TestRaceSliceVarWrite(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + s[3] = 3 + c <- true + }() + s = make([]int, 20) + <-c +} + +func TestRaceSliceVarRead(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + _ = s[3] + c <- true + }() + s = make([]int, 20) + <-c +} + +func TestRaceSliceVarRange(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + for range s { + } + c <- true + }() + s = make([]int, 20) + <-c +} + +func TestRaceSliceVarAppend(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + _ = append(s, 10) + c <- true + }() + s = make([]int, 20) + <-c +} + +func TestRaceSliceVarCopy(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + s2 := make([]int, 10) + copy(s, s2) + c <- true + }() + s = make([]int, 20) + <-c +} + +func TestRaceSliceVarCopy2(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + s2 := make([]int, 10) + copy(s2, s) + c <- true + }() + s = make([]int, 20) + <-c +} + +func TestRaceSliceAppend(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10, 20) + go func() { + _ = append(s, 1) + c <- true + }() + _ = append(s, 2) + <-c +} + +func TestRaceSliceAppendWrite(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + _ = append(s, 1) + c <- true + }() + s[0] = 42 + <-c +} + +func TestRaceSliceAppendSlice(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + go func() { + s2 := make([]int, 10) + _ = append(s, s2...) + c <- true + }() + s[0] = 42 + <-c +} + +func TestRaceSliceAppendSlice2(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + s2foobar := make([]int, 10) + go func() { + _ = append(s, s2foobar...) + c <- true + }() + s2foobar[5] = 42 + <-c +} + +func TestRaceSliceAppendString(t *testing.T) { + c := make(chan bool, 1) + s := make([]byte, 10) + go func() { + _ = append(s, "qwerty"...) + c <- true + }() + s[0] = 42 + <-c +} + +func TestRacePointerSliceAppend(t *testing.T) { + c := make(chan bool, 1) + s := make([]*int, 10, 20) + go func() { + _ = append(s, new(int)) + c <- true + }() + _ = append(s, new(int)) + <-c +} + +func TestRacePointerSliceAppendWrite(t *testing.T) { + c := make(chan bool, 1) + s := make([]*int, 10) + go func() { + _ = append(s, new(int)) + c <- true + }() + s[0] = new(int) + <-c +} + +func TestRacePointerSliceAppendSlice(t *testing.T) { + c := make(chan bool, 1) + s := make([]*int, 10) + go func() { + s2 := make([]*int, 10) + _ = append(s, s2...) + c <- true + }() + s[0] = new(int) + <-c +} + +func TestRacePointerSliceAppendSlice2(t *testing.T) { + c := make(chan bool, 1) + s := make([]*int, 10) + s2foobar := make([]*int, 10) + go func() { + _ = append(s, s2foobar...) + c <- true + }() + println("WRITE:", &s2foobar[5]) + s2foobar[5] = nil + <-c +} + +func TestNoRaceSliceIndexAccess(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + v := 0 + go func() { + _ = v + c <- true + }() + s[v] = 1 + <-c +} + +func TestNoRaceSliceIndexAccess2(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + v := 0 + go func() { + _ = v + c <- true + }() + _ = s[v] + <-c +} + +func TestRaceSliceIndexAccess(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + v := 0 + go func() { + v = 1 + c <- true + }() + s[v] = 1 + <-c +} + +func TestRaceSliceIndexAccess2(t *testing.T) { + c := make(chan bool, 1) + s := make([]int, 10) + v := 0 + go func() { + v = 1 + c <- true + }() + _ = s[v] + <-c +} + +func TestRaceSliceByteToString(t *testing.T) { + c := make(chan string) + s := make([]byte, 10) + go func() { + c <- string(s) + }() + s[0] = 42 + <-c +} + +func TestRaceSliceRuneToString(t *testing.T) { + c := make(chan string) + s := make([]rune, 10) + go func() { + c <- string(s) + }() + s[9] = 42 + <-c +} + +func TestRaceConcatString(t *testing.T) { + s := "hello" + c := make(chan string, 1) + go func() { + c <- s + " world" + }() + s = "world" + <-c +} + +func TestRaceCompareString(t *testing.T) { + s1 := "hello" + s2 := "world" + c := make(chan bool, 1) + go func() { + c <- s1 == s2 + }() + s1 = s2 + <-c +} + +func TestRaceSlice3(t *testing.T) { + done := make(chan bool) + x := make([]int, 10) + i := 2 + go func() { + i = 3 + done <- true + }() + _ = x[:1:i] + <-done +} + +var saved string + +func TestRaceSlice4(t *testing.T) { + // See issue 36794. + data := []byte("hello there") + var wg sync.WaitGroup + wg.Add(1) + go func() { + _ = string(data) + wg.Done() + }() + copy(data, data[2:]) + wg.Wait() +} diff --git a/src/runtime/race/testdata/sync_test.go b/src/runtime/race/testdata/sync_test.go new file mode 100644 index 0000000..b5fcd6c --- /dev/null +++ b/src/runtime/race/testdata/sync_test.go @@ -0,0 +1,202 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "sync" + "testing" + "time" +) + +func TestNoRaceCond(t *testing.T) { + x := 0 + _ = x + condition := 0 + var mu sync.Mutex + cond := sync.NewCond(&mu) + go func() { + x = 1 + mu.Lock() + condition = 1 + cond.Signal() + mu.Unlock() + }() + mu.Lock() + for condition != 1 { + cond.Wait() + } + mu.Unlock() + x = 2 +} + +func TestRaceCond(t *testing.T) { + done := make(chan bool) + var mu sync.Mutex + cond := sync.NewCond(&mu) + x := 0 + _ = x + condition := 0 + go func() { + time.Sleep(10 * time.Millisecond) // Enter cond.Wait loop + x = 1 + mu.Lock() + condition = 1 + cond.Signal() + mu.Unlock() + time.Sleep(10 * time.Millisecond) // Exit cond.Wait loop + mu.Lock() + x = 3 + mu.Unlock() + done <- true + }() + mu.Lock() + for condition != 1 { + cond.Wait() + } + mu.Unlock() + x = 2 + <-done +} + +// We do not currently automatically +// parse this test. It is intended that the creation +// stack is observed manually not to contain +// off-by-one errors +func TestRaceAnnounceThreads(t *testing.T) { + const N = 7 + allDone := make(chan bool, N) + + var x int + _ = x + + var f, g, h func() + f = func() { + x = 1 + go g() + go func() { + x = 1 + allDone <- true + }() + x = 2 + allDone <- true + } + + g = func() { + for i := 0; i < 2; i++ { + go func() { + x = 1 + allDone <- true + }() + allDone <- true + } + } + + h = func() { + x = 1 + x = 2 + go f() + allDone <- true + } + + go h() + + for i := 0; i < N; i++ { + <-allDone + } +} + +func TestNoRaceAfterFunc1(t *testing.T) { + i := 2 + c := make(chan bool) + var f func() + f = func() { + i-- + if i >= 0 { + time.AfterFunc(0, f) + } else { + c <- true + } + } + + time.AfterFunc(0, f) + <-c +} + +func TestNoRaceAfterFunc2(t *testing.T) { + var x int + _ = x + timer := time.AfterFunc(10, func() { + x = 1 + }) + defer timer.Stop() +} + +func TestNoRaceAfterFunc3(t *testing.T) { + c := make(chan bool, 1) + x := 0 + _ = x + time.AfterFunc(1e7, func() { + x = 1 + c <- true + }) + <-c +} + +func TestRaceAfterFunc3(t *testing.T) { + c := make(chan bool, 2) + x := 0 + _ = x + time.AfterFunc(1e7, func() { + x = 1 + c <- true + }) + time.AfterFunc(2e7, func() { + x = 2 + c <- true + }) + <-c + <-c +} + +// This test's output is intended to be +// observed manually. One should check +// that goroutine creation stack is +// comprehensible. +func TestRaceGoroutineCreationStack(t *testing.T) { + var x int + _ = x + var ch = make(chan bool, 1) + + f1 := func() { + x = 1 + ch <- true + } + f2 := func() { go f1() } + f3 := func() { go f2() } + f4 := func() { go f3() } + + go f4() + x = 2 + <-ch +} + +// A nil pointer in a mutex method call should not +// corrupt the race detector state. +// Used to hang indefinitely. +func TestNoRaceNilMutexCrash(t *testing.T) { + var mutex sync.Mutex + panics := 0 + defer func() { + if x := recover(); x != nil { + mutex.Lock() + panics++ + mutex.Unlock() + } else { + panic("no panic") + } + }() + var othermutex *sync.RWMutex + othermutex.RLock() +} diff --git a/src/runtime/race/testdata/waitgroup_test.go b/src/runtime/race/testdata/waitgroup_test.go new file mode 100644 index 0000000..1693373 --- /dev/null +++ b/src/runtime/race/testdata/waitgroup_test.go @@ -0,0 +1,360 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "runtime" + "sync" + "testing" + "time" +) + +func TestNoRaceWaitGroup(t *testing.T) { + var x int + _ = x + var wg sync.WaitGroup + n := 1 + for i := 0; i < n; i++ { + wg.Add(1) + j := i + go func() { + x = j + wg.Done() + }() + } + wg.Wait() +} + +func TestRaceWaitGroup(t *testing.T) { + var x int + _ = x + var wg sync.WaitGroup + n := 2 + for i := 0; i < n; i++ { + wg.Add(1) + j := i + go func() { + x = j + wg.Done() + }() + } + wg.Wait() +} + +func TestNoRaceWaitGroup2(t *testing.T) { + var x int + _ = x + var wg sync.WaitGroup + wg.Add(1) + go func() { + x = 1 + wg.Done() + }() + wg.Wait() + x = 2 +} + +// incrementing counter in Add and locking wg's mutex +func TestRaceWaitGroupAsMutex(t *testing.T) { + var x int + _ = x + var wg sync.WaitGroup + c := make(chan bool, 2) + go func() { + wg.Wait() + time.Sleep(100 * time.Millisecond) + wg.Add(+1) + x = 1 + wg.Add(-1) + c <- true + }() + go func() { + wg.Wait() + time.Sleep(100 * time.Millisecond) + wg.Add(+1) + x = 2 + wg.Add(-1) + c <- true + }() + <-c + <-c +} + +// Incorrect usage: Add is too late. +func TestRaceWaitGroupWrongWait(t *testing.T) { + c := make(chan bool, 2) + var x int + _ = x + var wg sync.WaitGroup + go func() { + wg.Add(1) + runtime.Gosched() + x = 1 + wg.Done() + c <- true + }() + go func() { + wg.Add(1) + runtime.Gosched() + x = 2 + wg.Done() + c <- true + }() + wg.Wait() + <-c + <-c +} + +func TestRaceWaitGroupWrongAdd(t *testing.T) { + c := make(chan bool, 2) + var wg sync.WaitGroup + go func() { + wg.Add(1) + time.Sleep(100 * time.Millisecond) + wg.Done() + c <- true + }() + go func() { + wg.Add(1) + time.Sleep(100 * time.Millisecond) + wg.Done() + c <- true + }() + time.Sleep(50 * time.Millisecond) + wg.Wait() + <-c + <-c +} + +func TestNoRaceWaitGroupMultipleWait(t *testing.T) { + c := make(chan bool, 2) + var wg sync.WaitGroup + go func() { + wg.Wait() + c <- true + }() + go func() { + wg.Wait() + c <- true + }() + wg.Wait() + <-c + <-c +} + +func TestNoRaceWaitGroupMultipleWait2(t *testing.T) { + c := make(chan bool, 2) + var wg sync.WaitGroup + wg.Add(2) + go func() { + wg.Done() + wg.Wait() + c <- true + }() + go func() { + wg.Done() + wg.Wait() + c <- true + }() + wg.Wait() + <-c + <-c +} + +func TestNoRaceWaitGroupMultipleWait3(t *testing.T) { + const P = 3 + var data [P]int + done := make(chan bool, P) + var wg sync.WaitGroup + wg.Add(P) + for p := 0; p < P; p++ { + go func(p int) { + data[p] = 42 + wg.Done() + }(p) + } + for p := 0; p < P; p++ { + go func() { + wg.Wait() + for p1 := 0; p1 < P; p1++ { + _ = data[p1] + } + done <- true + }() + } + for p := 0; p < P; p++ { + <-done + } +} + +// Correct usage but still a race +func TestRaceWaitGroup2(t *testing.T) { + var x int + _ = x + var wg sync.WaitGroup + wg.Add(2) + go func() { + x = 1 + wg.Done() + }() + go func() { + x = 2 + wg.Done() + }() + wg.Wait() +} + +func TestNoRaceWaitGroupPanicRecover(t *testing.T) { + var x int + _ = x + var wg sync.WaitGroup + defer func() { + err := recover() + if err != "sync: negative WaitGroup counter" { + t.Fatalf("Unexpected panic: %#v", err) + } + x = 2 + }() + x = 1 + wg.Add(-1) +} + +// TODO: this is actually a panic-synchronization test, not a +// WaitGroup test. Move it to another *_test file +// Is it possible to get a race by synchronization via panic? +func TestNoRaceWaitGroupPanicRecover2(t *testing.T) { + var x int + _ = x + var wg sync.WaitGroup + ch := make(chan bool, 1) + var f func() = func() { + x = 2 + ch <- true + } + go func() { + defer func() { + err := recover() + if err != "sync: negative WaitGroup counter" { + } + go f() + }() + x = 1 + wg.Add(-1) + }() + + <-ch +} + +func TestNoRaceWaitGroupTransitive(t *testing.T) { + x, y := 0, 0 + var wg sync.WaitGroup + wg.Add(2) + go func() { + x = 42 + wg.Done() + }() + go func() { + time.Sleep(1e7) + y = 42 + wg.Done() + }() + wg.Wait() + _ = x + _ = y +} + +func TestNoRaceWaitGroupReuse(t *testing.T) { + const P = 3 + var data [P]int + var wg sync.WaitGroup + for try := 0; try < 3; try++ { + wg.Add(P) + for p := 0; p < P; p++ { + go func(p int) { + data[p]++ + wg.Done() + }(p) + } + wg.Wait() + for p := 0; p < P; p++ { + data[p]++ + } + } +} + +func TestNoRaceWaitGroupReuse2(t *testing.T) { + const P = 3 + var data [P]int + var wg sync.WaitGroup + for try := 0; try < 3; try++ { + wg.Add(P) + for p := 0; p < P; p++ { + go func(p int) { + data[p]++ + wg.Done() + }(p) + } + done := make(chan bool) + go func() { + wg.Wait() + for p := 0; p < P; p++ { + data[p]++ + } + done <- true + }() + wg.Wait() + <-done + for p := 0; p < P; p++ { + data[p]++ + } + } +} + +func TestRaceWaitGroupReuse(t *testing.T) { + const P = 3 + const T = 3 + done := make(chan bool, T) + var wg sync.WaitGroup + for try := 0; try < T; try++ { + var data [P]int + wg.Add(P) + for p := 0; p < P; p++ { + go func(p int) { + time.Sleep(50 * time.Millisecond) + data[p]++ + wg.Done() + }(p) + } + go func() { + wg.Wait() + for p := 0; p < P; p++ { + data[p]++ + } + done <- true + }() + time.Sleep(100 * time.Millisecond) + wg.Wait() + } + for try := 0; try < T; try++ { + <-done + } +} + +func TestNoRaceWaitGroupConcurrentAdd(t *testing.T) { + const P = 4 + waiting := make(chan bool, P) + var wg sync.WaitGroup + for p := 0; p < P; p++ { + go func() { + wg.Add(1) + waiting <- true + wg.Done() + }() + } + for p := 0; p < P; p++ { + <-waiting + } + wg.Wait() +} |