| // 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 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 := 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 |
| } |
| } |