// 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"
|
"crypto/sha1"
|
"errors"
|
"fmt"
|
"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 interface{} = 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 interface{} = &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]interface{})
|
m[0] = make(map[int]interface{})
|
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 interface{}
|
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 interface{}) {
|
}(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 interface{}
|
go func() {
|
x = nil
|
c <- true
|
}()
|
_ = x
|
<-c
|
}
|
|
func TestRaceEmptyInterface2(t *testing.T) {
|
c := make(chan bool)
|
var x interface{}
|
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 interface{} = 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) {
|
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 {
|
n, err = f.Read(b)
|
total += n
|
if n > 0 {
|
in <- b[:n]
|
}
|
}
|
if err == io.EOF {
|
err = nil
|
}
|
}()
|
h := sha1.New()
|
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
|
}
|
}
|