mirror of
https://github.com/golang/go
synced 2024-11-12 04:00:23 -07:00
runtime/race: add unit tests for race detector
R=golang-dev, remyoudompheng, rsc CC=golang-dev https://golang.org/cl/6525052
This commit is contained in:
parent
d6fd52c088
commit
908e1b5ea1
152
src/pkg/runtime/race/race_test.go
Normal file
152
src/pkg/runtime/race/race_test.go
Normal file
@ -0,0 +1,152 @@
|
||||
// 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.
|
||||
|
||||
// +build race
|
||||
|
||||
// This program is used to verify the race detector
|
||||
// by running the tests and parsing their output.
|
||||
// It does not check stack correctness, completeness or anything else:
|
||||
// it merely verifies that if a test is expected to be racy
|
||||
// then the race is detected.
|
||||
package race_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
passedTests = 0
|
||||
totalTests = 0
|
||||
falsePos = 0
|
||||
falseNeg = 0
|
||||
failingPos = 0
|
||||
failingNeg = 0
|
||||
failed = false
|
||||
)
|
||||
|
||||
const (
|
||||
visibleLen = 40
|
||||
testPrefix = "=== RUN Test"
|
||||
)
|
||||
|
||||
func TestRace(t *testing.T) {
|
||||
testOutput, err := runTests()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to run tests: %v", err)
|
||||
}
|
||||
reader := bufio.NewReader(bytes.NewBuffer(testOutput))
|
||||
|
||||
funcName := ""
|
||||
var tsanLog []string
|
||||
for {
|
||||
s, err := nextLine(reader)
|
||||
if err != nil {
|
||||
fmt.Printf("%s\n", processLog(funcName, tsanLog))
|
||||
break
|
||||
}
|
||||
if strings.HasPrefix(s, testPrefix) {
|
||||
fmt.Printf("%s\n", processLog(funcName, tsanLog))
|
||||
tsanLog = make([]string, 0, 100)
|
||||
funcName = s[len(testPrefix):]
|
||||
} else {
|
||||
tsanLog = append(tsanLog, s)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("\nPassed %d of %d tests (%.02f%%, %d+, %d-)\n",
|
||||
passedTests, totalTests, 100*float64(passedTests)/float64(totalTests), falsePos, falseNeg)
|
||||
fmt.Printf("%d expected failures (%d has not fail)\n", failingPos+failingNeg, failingNeg)
|
||||
if failed {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// nextLine is a wrapper around bufio.Reader.ReadString.
|
||||
// It reads a line up to the next '\n' character. Error
|
||||
// is non-nil if there are no lines left, and nil
|
||||
// otherwise.
|
||||
func nextLine(r *bufio.Reader) (string, error) {
|
||||
s, err := r.ReadString('\n')
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
log.Fatalf("nextLine: expected EOF, received %v", err)
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
return s[:len(s)-1], nil
|
||||
}
|
||||
|
||||
// processLog verifies whether the given ThreadSanitizer's log
|
||||
// contains a race report, checks this information against
|
||||
// the name of the testcase and returns the result of this
|
||||
// comparison.
|
||||
func processLog(testName string, tsanLog []string) string {
|
||||
if !strings.HasPrefix(testName, "Race") && !strings.HasPrefix(testName, "NoRace") {
|
||||
return ""
|
||||
}
|
||||
gotRace := false
|
||||
for _, s := range tsanLog {
|
||||
if strings.Contains(s, "DATA RACE") {
|
||||
gotRace = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
failing := strings.Contains(testName, "Failing")
|
||||
expRace := !strings.HasPrefix(testName, "No")
|
||||
for len(testName) < visibleLen {
|
||||
testName += " "
|
||||
}
|
||||
if expRace == gotRace {
|
||||
passedTests++
|
||||
totalTests++
|
||||
if failing {
|
||||
failed = true
|
||||
failingNeg++
|
||||
}
|
||||
return fmt.Sprintf("%s .", testName)
|
||||
}
|
||||
pos := ""
|
||||
if expRace {
|
||||
falseNeg++
|
||||
} else {
|
||||
falsePos++
|
||||
pos = "+"
|
||||
}
|
||||
if failing {
|
||||
failingPos++
|
||||
} else {
|
||||
failed = true
|
||||
}
|
||||
totalTests++
|
||||
return fmt.Sprintf("%s %s%s", testName, "FAILED", pos)
|
||||
}
|
||||
|
||||
// runTests assures that the package and its dependencies is
|
||||
// built with instrumentation enabled and returns the output of 'go test'
|
||||
// which includes possible data race reports from ThreadSanitizer.
|
||||
func runTests() ([]byte, error) {
|
||||
tests, err := filepath.Glob("./testdata/*_test.go")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args := []string{"test", "-race", "-v"}
|
||||
args = append(args, tests...)
|
||||
cmd := exec.Command("go", args...)
|
||||
// The following flags turn off heuristics that suppress seemingly identical reports.
|
||||
// It is required because the tests contain a lot of data races on the same addresses
|
||||
// (the tests are simple and the memory is constantly reused).
|
||||
cmd.Env = append(os.Environ(), `GORACE="suppress_equal_stacks=0 suppress_equal_addresses=0"`)
|
||||
ret, _ := cmd.CombinedOutput()
|
||||
return ret, nil
|
||||
}
|
271
src/pkg/runtime/race/testdata/atomic_test.go
vendored
Normal file
271
src/pkg/runtime/race/testdata/atomic_test.go
vendored
Normal file
@ -0,0 +1,271 @@
|
||||
// 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/atomic"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func TestNoRaceAtomicAddInt64(t *testing.T) {
|
||||
var x1, x2 int8
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
var s uint64
|
||||
go func() {
|
||||
x = 2
|
||||
atomic.StoreUint64(&s, 1)
|
||||
}()
|
||||
for !atomic.CompareAndSwapUint64(&s, 1, 0) {
|
||||
runtime.Gosched()
|
||||
}
|
||||
x = 1
|
||||
}
|
||||
|
||||
// Races with non-atomic loads are not detected.
|
||||
func TestRaceFailingAtomicStoreLoad(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
|
||||
}
|
||||
|
||||
// Races with non-atomic loads are not detected.
|
||||
func TestRaceFailingAtomicAddLoad(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
|
||||
}
|
20
src/pkg/runtime/race/testdata/cgo_test.go
vendored
Normal file
20
src/pkg/runtime/race/testdata/cgo_test.go
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 (
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNoRaceCgoSync(t *testing.T) {
|
||||
cmd := exec.Command("go", "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)
|
||||
}
|
||||
}
|
40
src/pkg/runtime/race/testdata/cgo_test_main.go
vendored
Normal file
40
src/pkg/runtime/race/testdata/cgo_test_main.go
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// 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
|
||||
|
||||
/*
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
|
||||
int sync;
|
||||
|
||||
void Notify(void)
|
||||
{
|
||||
pthread_mutex_lock(&mtx);
|
||||
sync = 1;
|
||||
pthread_cond_broadcast(&cv);
|
||||
pthread_mutex_unlock(&mtx);
|
||||
}
|
||||
|
||||
void Wait(void)
|
||||
{
|
||||
pthread_mutex_lock(&mtx);
|
||||
while(sync == 0)
|
||||
pthread_cond_wait(&cv, &mtx);
|
||||
pthread_mutex_unlock(&mtx);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
data := 0
|
||||
go func() {
|
||||
data = 1
|
||||
C.Notify()
|
||||
}()
|
||||
C.Wait()
|
||||
_ = data
|
||||
}
|
457
src/pkg/runtime/race/testdata/chan_test.go
vendored
Normal file
457
src/pkg/runtime/race/testdata/chan_test.go
vendored
Normal file
@ -0,0 +1,457 @@
|
||||
// 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
|
||||
c := make(chan int)
|
||||
go func() {
|
||||
v = 1
|
||||
c <- 0
|
||||
}()
|
||||
<-c
|
||||
v = 2
|
||||
}
|
||||
|
||||
func TestNoRaceChanSyncRev(t *testing.T) {
|
||||
v := 0
|
||||
c := make(chan int)
|
||||
go func() {
|
||||
c <- 0
|
||||
v = 2
|
||||
}()
|
||||
v = 1
|
||||
<-c
|
||||
}
|
||||
|
||||
func TestNoRaceChanAsync(t *testing.T) {
|
||||
v := 0
|
||||
c := make(chan int, 10)
|
||||
go func() {
|
||||
v = 1
|
||||
c <- 0
|
||||
}()
|
||||
<-c
|
||||
v = 2
|
||||
}
|
||||
|
||||
func TestRaceChanAsyncRev(t *testing.T) {
|
||||
v := 0
|
||||
c := make(chan int, 10)
|
||||
go func() {
|
||||
c <- 0
|
||||
v = 1
|
||||
}()
|
||||
v = 2
|
||||
<-c
|
||||
}
|
||||
|
||||
func TestNoRaceChanAsyncCloseRecv(t *testing.T) {
|
||||
v := 0
|
||||
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
|
||||
c := make(chan int, 10)
|
||||
go func() {
|
||||
v = 1
|
||||
close(c)
|
||||
}()
|
||||
_, _ = <-c
|
||||
v = 2
|
||||
}
|
||||
|
||||
func TestNoRaceChanAsyncCloseRecv3(t *testing.T) {
|
||||
v := 0
|
||||
c := make(chan int, 10)
|
||||
go func() {
|
||||
v = 1
|
||||
close(c)
|
||||
}()
|
||||
for _ = range c {
|
||||
}
|
||||
v = 2
|
||||
}
|
||||
|
||||
func TestNoRaceChanSyncCloseRecv(t *testing.T) {
|
||||
v := 0
|
||||
c := make(chan int)
|
||||
go func() {
|
||||
v = 1
|
||||
close(c)
|
||||
}()
|
||||
func() {
|
||||
defer func() {
|
||||
recover()
|
||||
v = 2
|
||||
}()
|
||||
<-c
|
||||
}()
|
||||
}
|
||||
|
||||
func TestNoRaceChanSyncCloseRecv2(t *testing.T) {
|
||||
v := 0
|
||||
c := make(chan int)
|
||||
go func() {
|
||||
v = 1
|
||||
close(c)
|
||||
}()
|
||||
_, _ = <-c
|
||||
v = 2
|
||||
}
|
||||
|
||||
func TestNoRaceChanSyncCloseRecv3(t *testing.T) {
|
||||
v := 0
|
||||
c := make(chan int)
|
||||
go func() {
|
||||
v = 1
|
||||
close(c)
|
||||
}()
|
||||
for _ = range c {
|
||||
}
|
||||
v = 2
|
||||
}
|
||||
|
||||
func TestRaceChanSyncCloseSend(t *testing.T) {
|
||||
v := 0
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
c := make(chan int, 1)
|
||||
go func() {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
v1 = 1
|
||||
c <- 1
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(1e7)
|
||||
v2 = 2
|
||||
close(c)
|
||||
}()
|
||||
time.Sleep(2e7)
|
||||
if _, who := <-c; who {
|
||||
v2 = 2
|
||||
} else {
|
||||
v1 = 2
|
||||
}
|
||||
}
|
||||
|
||||
func TestRaceChanSendClose(t *testing.T) {
|
||||
compl := make(chan bool, 2)
|
||||
c := make(chan int, 1)
|
||||
go func() {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
c <- 1
|
||||
compl <- true
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(1e7)
|
||||
close(c)
|
||||
compl <- true
|
||||
}()
|
||||
<-compl
|
||||
<-compl
|
||||
}
|
||||
|
||||
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 TestRaceChanCloseLen(t *testing.T) {
|
||||
v := 0
|
||||
c := make(chan int, 10)
|
||||
c <- 0
|
||||
go func() {
|
||||
v = 1
|
||||
close(c)
|
||||
}()
|
||||
time.Sleep(1e7)
|
||||
_ = len(c)
|
||||
v = 2
|
||||
}
|
||||
|
||||
func TestRaceChanSameCell(t *testing.T) {
|
||||
c := make(chan int, 1)
|
||||
v := 0
|
||||
go func() {
|
||||
v = 1
|
||||
c <- 42
|
||||
<-c
|
||||
}()
|
||||
time.Sleep(1e7)
|
||||
c <- 43
|
||||
<-c
|
||||
_ = v
|
||||
}
|
||||
|
||||
func TestRaceChanCloseSend(t *testing.T) {
|
||||
compl := make(chan bool, 1)
|
||||
c := make(chan int, 10)
|
||||
go func() {
|
||||
close(c)
|
||||
compl <- true
|
||||
}()
|
||||
c <- 0
|
||||
<-compl
|
||||
}
|
132
src/pkg/runtime/race/testdata/comp_test.go
vendored
Normal file
132
src/pkg/runtime/race/testdata/comp_test.go
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
// 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 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
|
||||
}
|
67
src/pkg/runtime/race/testdata/finalizer_test.go
vendored
Normal file
67
src/pkg/runtime/race/testdata/finalizer_test.go
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
// 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(int)
|
||||
runtime.SetFinalizer(x, func(x *int) {
|
||||
*x = 42
|
||||
})
|
||||
*x = 66
|
||||
c <- true
|
||||
}()
|
||||
<-c
|
||||
runtime.GC()
|
||||
time.Sleep(1e8)
|
||||
}
|
||||
|
||||
var finVar struct {
|
||||
sync.Mutex
|
||||
cnt int
|
||||
}
|
||||
|
||||
func TestNoRaceFinGlobal(t *testing.T) {
|
||||
c := make(chan bool)
|
||||
go func() {
|
||||
x := new(int)
|
||||
runtime.SetFinalizer(x, func(x *int) {
|
||||
finVar.Lock()
|
||||
finVar.cnt++
|
||||
finVar.Unlock()
|
||||
})
|
||||
c <- true
|
||||
}()
|
||||
<-c
|
||||
runtime.GC()
|
||||
time.Sleep(1e8)
|
||||
finVar.Lock()
|
||||
finVar.cnt++
|
||||
finVar.Unlock()
|
||||
}
|
||||
|
||||
func TestRaceFin(t *testing.T) {
|
||||
c := make(chan bool)
|
||||
y := 0
|
||||
go func() {
|
||||
x := new(int)
|
||||
runtime.SetFinalizer(x, func(x *int) {
|
||||
y = 42
|
||||
})
|
||||
c <- true
|
||||
}()
|
||||
<-c
|
||||
runtime.GC()
|
||||
time.Sleep(1e8)
|
||||
y = 66
|
||||
}
|
69
src/pkg/runtime/race/testdata/io_test.go
vendored
Normal file
69
src/pkg/runtime/race/testdata/io_test.go
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
// 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"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNoRaceIOFile(t *testing.T) {
|
||||
x := 0
|
||||
path, _ := ioutil.TempDir("", "race_test")
|
||||
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
|
||||
}
|
||||
|
||||
func TestNoRaceIOHttp(t *testing.T) {
|
||||
x := 0
|
||||
go func() {
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
x = 41
|
||||
fmt.Fprintf(w, "test")
|
||||
x = 42
|
||||
})
|
||||
err := http.ListenAndServe(":23651", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("http.ListenAndServe: %v", err)
|
||||
}
|
||||
}()
|
||||
time.Sleep(1e7)
|
||||
x = 1
|
||||
_, err := http.Get("http://127.0.0.1:23651")
|
||||
if err != nil {
|
||||
t.Fatalf("http.Get: %v", err)
|
||||
}
|
||||
x = 2
|
||||
_, err = http.Get("http://127.0.0.1:23651")
|
||||
if err != nil {
|
||||
t.Fatalf("http.Get: %v", err)
|
||||
}
|
||||
x = 3
|
||||
}
|
151
src/pkg/runtime/race/testdata/map_test.go
vendored
Normal file
151
src/pkg/runtime/race/testdata/map_test.go
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
// 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 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
|
||||
}
|
||||
|
||||
// Map len is not instrumented.
|
||||
func TestRaceFailingMapLen(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
|
||||
}
|
||||
|
||||
// Map len is not instrumented.
|
||||
func TestRaceFailingMapLenDelete(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)
|
||||
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
|
||||
}
|
1363
src/pkg/runtime/race/testdata/mop_test.go
vendored
Normal file
1363
src/pkg/runtime/race/testdata/mop_test.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
138
src/pkg/runtime/race/testdata/mutex_test.go
vendored
Normal file
138
src/pkg/runtime/race/testdata/mutex_test.go
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// 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
|
||||
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
|
||||
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
|
||||
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
|
||||
ch := make(chan bool, 2)
|
||||
go func() {
|
||||
x = 1
|
||||
mu.Lock()
|
||||
mu.Unlock()
|
||||
ch <- true
|
||||
}()
|
||||
go func() {
|
||||
<-time.After(1e5)
|
||||
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
|
||||
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
|
||||
}
|
123
src/pkg/runtime/race/testdata/regression_test.go
vendored
Normal file
123
src/pkg/runtime/race/testdata/regression_test.go
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
// 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) {
|
||||
go func() {
|
||||
_ = l
|
||||
}()
|
||||
l = LogImpl{}
|
||||
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])
|
||||
}
|
||||
|
||||
type Rect struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
min, max Rect
|
||||
}
|
||||
|
||||
func NewImage() Image {
|
||||
var pleaseDoNotInlineMe stack
|
||||
pleaseDoNotInlineMe.push(1)
|
||||
_ = pleaseDoNotInlineMe.pop()
|
||||
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
|
||||
|
||||
func makeChan() *RpcChan {
|
||||
var pleaseDoNotInlineMe stack
|
||||
pleaseDoNotInlineMe.push(1)
|
||||
_ = pleaseDoNotInlineMe.pop()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
134
src/pkg/runtime/race/testdata/rwmutex_test.go
vendored
Normal file
134
src/pkg/runtime/race/testdata/rwmutex_test.go
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
// 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
|
||||
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
|
||||
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, 3)
|
||||
go func() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
x = 2
|
||||
ch <- true
|
||||
}()
|
||||
go func() {
|
||||
mu.RLock()
|
||||
y = x + 1
|
||||
mu.RUnlock()
|
||||
ch <- true
|
||||
}()
|
||||
go func() {
|
||||
mu.RLock()
|
||||
y = x + 2
|
||||
mu.RUnlock()
|
||||
ch <- true
|
||||
}()
|
||||
<-ch
|
||||
<-ch
|
||||
<-ch
|
||||
_ = y
|
||||
}
|
||||
|
||||
func TestNoRaceRWMutexMultipleReaders(t *testing.T) {
|
||||
var mu sync.RWMutex
|
||||
x := int64(0)
|
||||
ch := make(chan bool, 3)
|
||||
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
|
||||
}()
|
||||
<-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
|
||||
}
|
286
src/pkg/runtime/race/testdata/select_test.go
vendored
Normal file
286
src/pkg/runtime/race/testdata/select_test.go
vendored
Normal file
@ -0,0 +1,286 @@
|
||||
// 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
|
||||
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/chan.c:^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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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 (unconditionaly) 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
|
||||
}
|
||||
*/
|
445
src/pkg/runtime/race/testdata/slice_test.go
vendored
Normal file
445
src/pkg/runtime/race/testdata/slice_test.go
vendored
Normal file
@ -0,0 +1,445 @@
|
||||
// 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 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 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
|
||||
}
|
||||
|
||||
// Not implemented.
|
||||
func TestRaceFailingSliceAppend(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 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
|
||||
}
|
197
src/pkg/runtime/race/testdata/sync_test.go
vendored
Normal file
197
src/pkg/runtime/race/testdata/sync_test.go
vendored
Normal file
@ -0,0 +1,197 @@
|
||||
// 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) { // tsan's test02
|
||||
ch := make(chan bool, 1)
|
||||
var x int = 0
|
||||
var mu sync.Mutex
|
||||
var cond *sync.Cond = sync.NewCond(&mu)
|
||||
var condition int = 0
|
||||
var waker func()
|
||||
waker = func() {
|
||||
x = 1
|
||||
mu.Lock()
|
||||
condition = 1
|
||||
cond.Signal()
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
var waiter func()
|
||||
waiter = func() {
|
||||
go waker()
|
||||
cond.L.Lock()
|
||||
for condition != 1 {
|
||||
cond.Wait()
|
||||
}
|
||||
cond.L.Unlock()
|
||||
x = 2
|
||||
ch <- true
|
||||
}
|
||||
go waiter()
|
||||
<-ch
|
||||
}
|
||||
|
||||
func TestRaceCond(t *testing.T) { // tsan's test50
|
||||
ch := make(chan bool, 2)
|
||||
|
||||
var x int = 0
|
||||
var mu sync.Mutex
|
||||
var condition int = 0
|
||||
var cond *sync.Cond = sync.NewCond(&mu)
|
||||
|
||||
var waker func() = func() {
|
||||
<-time.After(1e5)
|
||||
x = 1
|
||||
mu.Lock()
|
||||
condition = 1
|
||||
cond.Signal()
|
||||
mu.Unlock()
|
||||
<-time.After(1e5)
|
||||
mu.Lock()
|
||||
x = 3
|
||||
mu.Unlock()
|
||||
ch <- true
|
||||
}
|
||||
|
||||
var waiter func() = func() {
|
||||
mu.Lock()
|
||||
for condition != 1 {
|
||||
cond.Wait()
|
||||
}
|
||||
mu.Unlock()
|
||||
x = 2
|
||||
ch <- true
|
||||
}
|
||||
x = 0
|
||||
go waker()
|
||||
go waiter()
|
||||
<-ch
|
||||
<-ch
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
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
|
||||
timer := time.AfterFunc(10, func() {
|
||||
x = 1
|
||||
})
|
||||
defer timer.Stop()
|
||||
_ = x
|
||||
}
|
||||
|
||||
func TestNoRaceAfterFunc3(t *testing.T) {
|
||||
c := make(chan bool, 1)
|
||||
x := 0
|
||||
time.AfterFunc(1e7, func() {
|
||||
x = 1
|
||||
c <- true
|
||||
})
|
||||
<-c
|
||||
}
|
||||
|
||||
func TestRaceAfterFunc3(t *testing.T) {
|
||||
c := make(chan bool, 2)
|
||||
x := 0
|
||||
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
|
||||
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
|
||||
}
|
232
src/pkg/runtime/race/testdata/waitgroup_test.go
vendored
Normal file
232
src/pkg/runtime/race/testdata/waitgroup_test.go
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
// 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
// A common WaitGroup misuse that can potentially be caught be the race detector.
|
||||
// For this simple case we must emulate Add() as read on &wg and Wait() as write on &wg.
|
||||
// However it will have false positives if there are several concurrent Wait() calls.
|
||||
func TestRaceFailingWaitGroupWrongAdd(t *testing.T) {
|
||||
c := make(chan bool, 2)
|
||||
var wg sync.WaitGroup
|
||||
go func() {
|
||||
wg.Add(1)
|
||||
wg.Done()
|
||||
c <- true
|
||||
}()
|
||||
go func() {
|
||||
wg.Add(1)
|
||||
wg.Done()
|
||||
c <- true
|
||||
}()
|
||||
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
|
||||
}
|
||||
|
||||
// Correct usage but still a race
|
||||
func TestRaceWaitGroup2(t *testing.T) {
|
||||
var x int
|
||||
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
|
||||
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
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user