summaryrefslogtreecommitdiffstats
path: root/src/runtime/race
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/race')
-rw-r--r--src/runtime/race/README15
-rw-r--r--src/runtime/race/doc.go9
-rw-r--r--src/runtime/race/output_test.go442
-rw-r--r--src/runtime/race/race.go15
-rw-r--r--src/runtime/race/race_darwin_amd64.sysobin0 -> 455944 bytes
-rw-r--r--src/runtime/race/race_darwin_arm64.sysobin0 -> 438560 bytes
-rw-r--r--src/runtime/race/race_freebsd_amd64.sysobin0 -> 583264 bytes
-rw-r--r--src/runtime/race/race_linux_amd64.sysobin0 -> 525176 bytes
-rw-r--r--src/runtime/race/race_linux_arm64.sysobin0 -> 505224 bytes
-rw-r--r--src/runtime/race/race_linux_ppc64le.sysobin0 -> 624648 bytes
-rw-r--r--src/runtime/race/race_linux_test.go37
-rw-r--r--src/runtime/race/race_netbsd_amd64.sysobin0 -> 609424 bytes
-rw-r--r--src/runtime/race/race_openbsd_amd64.sysobin0 -> 688784 bytes
-rw-r--r--src/runtime/race/race_test.go250
-rw-r--r--src/runtime/race/race_unix_test.go29
-rw-r--r--src/runtime/race/race_windows_amd64.sysobin0 -> 461185 bytes
-rw-r--r--src/runtime/race/race_windows_test.go46
-rw-r--r--src/runtime/race/sched_test.go48
-rw-r--r--src/runtime/race/syso_test.go33
-rw-r--r--src/runtime/race/testdata/atomic_test.go325
-rw-r--r--src/runtime/race/testdata/cgo_test.go21
-rw-r--r--src/runtime/race/testdata/cgo_test_main.go30
-rw-r--r--src/runtime/race/testdata/chan_test.go787
-rw-r--r--src/runtime/race/testdata/comp_test.go186
-rw-r--r--src/runtime/race/testdata/finalizer_test.go68
-rw-r--r--src/runtime/race/testdata/io_test.go75
-rw-r--r--src/runtime/race/testdata/issue12225_test.go20
-rw-r--r--src/runtime/race/testdata/issue12664_test.go76
-rw-r--r--src/runtime/race/testdata/issue13264_test.go13
-rw-r--r--src/runtime/race/testdata/map_test.go335
-rw-r--r--src/runtime/race/testdata/mop_test.go2082
-rw-r--r--src/runtime/race/testdata/mutex_test.go150
-rw-r--r--src/runtime/race/testdata/pool_test.go47
-rw-r--r--src/runtime/race/testdata/reflect_test.go46
-rw-r--r--src/runtime/race/testdata/regression_test.go189
-rw-r--r--src/runtime/race/testdata/rwmutex_test.go154
-rw-r--r--src/runtime/race/testdata/select_test.go293
-rw-r--r--src/runtime/race/testdata/slice_test.go608
-rw-r--r--src/runtime/race/testdata/sync_test.go202
-rw-r--r--src/runtime/race/testdata/waitgroup_test.go360
-rw-r--r--src/runtime/race/timer_test.go33
41 files changed, 7024 insertions, 0 deletions
diff --git a/src/runtime/race/README b/src/runtime/race/README
new file mode 100644
index 0000000..d3c5518
--- /dev/null
+++ b/src/runtime/race/README
@@ -0,0 +1,15 @@
+runtime/race package contains the data race detector runtime library.
+It is based on ThreadSanitizer race detector, that is currently a part of
+the LLVM project (https://github.com/llvm/llvm-project/tree/main/compiler-rt).
+
+To update the .syso files use golang.org/x/build/cmd/racebuild.
+
+race_darwin_amd64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 with https://reviews.llvm.org/D114825 applied and Go 7ccbcc90560468937f02609a43cb39a6e13ff797.
+race_freebsd_amd64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b.
+race_linux_amd64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b.
+race_linux_ppc64le.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b.
+race_netbsd_amd64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b.
+race_windows_amd64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b.
+race_linux_arm64.syso built with LLVM 89f7ccea6f6488c443655880229c54db1f180153 and Go f62d3202bf9dbb3a00ad2a2c63ff4fa4188c5d3b.
+race_darwin_arm64.syso built with LLVM 00da38ce2d36c07f12c287dc515d37bb7bc410e9 with https://reviews.llvm.org/D114825 applied and Go 7ccbcc90560468937f02609a43cb39a6e13ff797.
+race_openbsd_amd64.syso built with LLVM fcf6ae2f070eba73074b6ec8d8281e54d29dbeeb and Go 8f2db14cd35bbd674cb2988a508306de6655e425.
diff --git a/src/runtime/race/doc.go b/src/runtime/race/doc.go
new file mode 100644
index 0000000..9e93f66
--- /dev/null
+++ b/src/runtime/race/doc.go
@@ -0,0 +1,9 @@
+// Copyright 2013 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 implements data race detection logic.
+// No public interface is provided.
+// For details about the race detector see
+// https://golang.org/doc/articles/race_detector.html
+package race
diff --git a/src/runtime/race/output_test.go b/src/runtime/race/output_test.go
new file mode 100644
index 0000000..0dcdabe
--- /dev/null
+++ b/src/runtime/race/output_test.go
@@ -0,0 +1,442 @@
+// Copyright 2013 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.
+
+//go:build race
+
+package race_test
+
+import (
+ "fmt"
+ "internal/testenv"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+func TestOutput(t *testing.T) {
+ pkgdir := t.TempDir()
+ out, err := exec.Command(testenv.GoToolPath(t), "install", "-race", "-pkgdir="+pkgdir, "testing").CombinedOutput()
+ if err != nil {
+ t.Fatalf("go install -race: %v\n%s", err, out)
+ }
+
+ for _, test := range tests {
+ if test.goos != "" && test.goos != runtime.GOOS {
+ t.Logf("test %v runs only on %v, skipping: ", test.name, test.goos)
+ continue
+ }
+ dir := t.TempDir()
+ source := "main.go"
+ if test.run == "test" {
+ source = "main_test.go"
+ }
+ src := filepath.Join(dir, source)
+ f, err := os.Create(src)
+ if err != nil {
+ t.Fatalf("failed to create file: %v", err)
+ }
+ _, err = f.WriteString(test.source)
+ if err != nil {
+ f.Close()
+ t.Fatalf("failed to write: %v", err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatalf("failed to close file: %v", err)
+ }
+
+ cmd := exec.Command(testenv.GoToolPath(t), test.run, "-race", "-pkgdir="+pkgdir, src)
+ // GODEBUG spoils program output, GOMAXPROCS makes it flaky.
+ for _, env := range os.Environ() {
+ if strings.HasPrefix(env, "GODEBUG=") ||
+ strings.HasPrefix(env, "GOMAXPROCS=") ||
+ strings.HasPrefix(env, "GORACE=") {
+ continue
+ }
+ cmd.Env = append(cmd.Env, env)
+ }
+ cmd.Env = append(cmd.Env,
+ "GOMAXPROCS=1", // see comment in race_test.go
+ "GORACE="+test.gorace,
+ )
+ got, _ := cmd.CombinedOutput()
+ matched := false
+ for _, re := range test.re {
+ if regexp.MustCompile(re).MatchString(string(got)) {
+ matched = true
+ break
+ }
+ }
+ if !matched {
+ exp := fmt.Sprintf("expect:\n%v\n", test.re[0])
+ if len(test.re) > 1 {
+ exp = fmt.Sprintf("expected one of %d patterns:\n",
+ len(test.re))
+ for k, re := range test.re {
+ exp += fmt.Sprintf("pattern %d:\n%v\n", k, re)
+ }
+ }
+ t.Fatalf("failed test case %v, %sgot:\n%s",
+ test.name, exp, got)
+ }
+ }
+}
+
+var tests = []struct {
+ name string
+ run string
+ goos string
+ gorace string
+ source string
+ re []string
+}{
+ {"simple", "run", "", "atexit_sleep_ms=0", `
+package main
+import "time"
+var xptr *int
+var donechan chan bool
+func main() {
+ done := make(chan bool)
+ x := 0
+ startRacer(&x, done)
+ store(&x, 43)
+ <-done
+}
+func store(x *int, v int) {
+ *x = v
+}
+func startRacer(x *int, done chan bool) {
+ xptr = x
+ donechan = done
+ go racer()
+}
+func racer() {
+ time.Sleep(10*time.Millisecond)
+ store(xptr, 42)
+ donechan <- true
+}
+`, []string{`==================
+WARNING: DATA RACE
+Write at 0x[0-9,a-f]+ by goroutine [0-9]:
+ main\.store\(\)
+ .+/main\.go:14 \+0x[0-9,a-f]+
+ main\.racer\(\)
+ .+/main\.go:23 \+0x[0-9,a-f]+
+
+Previous write at 0x[0-9,a-f]+ by main goroutine:
+ main\.store\(\)
+ .+/main\.go:14 \+0x[0-9,a-f]+
+ main\.main\(\)
+ .+/main\.go:10 \+0x[0-9,a-f]+
+
+Goroutine [0-9] \(running\) created at:
+ main\.startRacer\(\)
+ .+/main\.go:19 \+0x[0-9,a-f]+
+ main\.main\(\)
+ .+/main\.go:9 \+0x[0-9,a-f]+
+==================
+Found 1 data race\(s\)
+exit status 66
+`}},
+
+ {"exitcode", "run", "", "atexit_sleep_ms=0 exitcode=13", `
+package main
+func main() {
+ done := make(chan bool)
+ x := 0; _ = x
+ go func() {
+ x = 42
+ done <- true
+ }()
+ x = 43
+ <-done
+}
+`, []string{`exit status 13`}},
+
+ {"strip_path_prefix", "run", "", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
+package main
+func main() {
+ done := make(chan bool)
+ x := 0; _ = x
+ go func() {
+ x = 42
+ done <- true
+ }()
+ x = 43
+ <-done
+}
+`, []string{`
+ go:7 \+0x[0-9,a-f]+
+`}},
+
+ {"halt_on_error", "run", "", "atexit_sleep_ms=0 halt_on_error=1", `
+package main
+func main() {
+ done := make(chan bool)
+ x := 0; _ = x
+ go func() {
+ x = 42
+ done <- true
+ }()
+ x = 43
+ <-done
+}
+`, []string{`
+==================
+exit status 66
+`}},
+
+ {"test_fails_on_race", "test", "", "atexit_sleep_ms=0", `
+package main_test
+import "testing"
+func TestFail(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ _ = x
+ go func() {
+ x = 42
+ done <- true
+ }()
+ x = 43
+ <-done
+ t.Log(t.Failed())
+}
+`, []string{`
+==================
+--- FAIL: TestFail \([0-9.]+s\)
+.*main_test.go:14: true
+.*testing.go:.*: race detected during execution of test
+FAIL`}},
+
+ {"slicebytetostring_pc", "run", "", "atexit_sleep_ms=0", `
+package main
+func main() {
+ done := make(chan string)
+ data := make([]byte, 10)
+ go func() {
+ done <- string(data)
+ }()
+ data[0] = 1
+ <-done
+}
+`, []string{`
+ runtime\.slicebytetostring\(\)
+ .*/runtime/string\.go:.*
+ main\.main\.func1\(\)
+ .*/main.go:7`}},
+
+ // Test for https://golang.org/issue/33309
+ {"midstack_inlining_traceback", "run", "linux", "atexit_sleep_ms=0", `
+package main
+
+var x int
+var c chan int
+func main() {
+ c = make(chan int)
+ go f()
+ x = 1
+ <-c
+}
+
+func f() {
+ g(c)
+}
+
+func g(c chan int) {
+ h(c)
+}
+
+func h(c chan int) {
+ c <- x
+}
+`, []string{`==================
+WARNING: DATA RACE
+Read at 0x[0-9,a-f]+ by goroutine [0-9]:
+ main\.h\(\)
+ .+/main\.go:22 \+0x[0-9,a-f]+
+ main\.g\(\)
+ .+/main\.go:18 \+0x[0-9,a-f]+
+ main\.f\(\)
+ .+/main\.go:14 \+0x[0-9,a-f]+
+
+Previous write at 0x[0-9,a-f]+ by main goroutine:
+ main\.main\(\)
+ .+/main\.go:9 \+0x[0-9,a-f]+
+
+Goroutine [0-9] \(running\) created at:
+ main\.main\(\)
+ .+/main\.go:8 \+0x[0-9,a-f]+
+==================
+Found 1 data race\(s\)
+exit status 66
+`}},
+
+ // Test for https://golang.org/issue/17190
+ {"external_cgo_thread", "run", "linux", "atexit_sleep_ms=0", `
+package main
+
+/*
+#include <pthread.h>
+typedef struct cb {
+ int foo;
+} cb;
+extern void goCallback();
+static inline void *threadFunc(void *p) {
+ goCallback();
+ return 0;
+}
+static inline void startThread(cb* c) {
+ pthread_t th;
+ pthread_create(&th, 0, threadFunc, 0);
+}
+*/
+import "C"
+
+var done chan bool
+var racy int
+
+//export goCallback
+func goCallback() {
+ racy++
+ done <- true
+}
+
+func main() {
+ done = make(chan bool)
+ var c C.cb
+ C.startThread(&c)
+ racy++
+ <- done
+}
+`, []string{`==================
+WARNING: DATA RACE
+Read at 0x[0-9,a-f]+ by main goroutine:
+ main\.main\(\)
+ .*/main\.go:34 \+0x[0-9,a-f]+
+
+Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:
+ main\.goCallback\(\)
+ .*/main\.go:27 \+0x[0-9,a-f]+
+ _cgoexp_[0-9a-z]+_goCallback\(\)
+ .*_cgo_gotypes\.go:[0-9]+ \+0x[0-9,a-f]+
+ _cgoexp_[0-9a-z]+_goCallback\(\)
+ <autogenerated>:1 \+0x[0-9,a-f]+
+
+Goroutine [0-9] \(running\) created at:
+ runtime\.newextram\(\)
+ .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
+==================`,
+ `==================
+WARNING: DATA RACE
+Read at 0x[0-9,a-f]+ by .*:
+ main\..*
+ .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*
+
+Previous write at 0x[0-9,a-f]+ by .*:
+ main\..*
+ .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*
+
+Goroutine [0-9] \(running\) created at:
+ runtime\.newextram\(\)
+ .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
+==================`}},
+ {"second_test_passes", "test", "", "atexit_sleep_ms=0", `
+package main_test
+import "testing"
+func TestFail(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ _ = x
+ go func() {
+ x = 42
+ done <- true
+ }()
+ x = 43
+ <-done
+}
+
+func TestPass(t *testing.T) {
+}
+`, []string{`
+==================
+--- FAIL: TestFail \([0-9.]+s\)
+.*testing.go:.*: race detected during execution of test
+FAIL`}},
+ {"mutex", "run", "", "atexit_sleep_ms=0", `
+package main
+import (
+ "sync"
+ "fmt"
+)
+func main() {
+ c := make(chan bool, 1)
+ threads := 1
+ iterations := 20000
+ data := 0
+ var wg sync.WaitGroup
+ for i := 0; i < threads; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < iterations; i++ {
+ c <- true
+ data += 1
+ <- c
+ }
+ }()
+ }
+ for i := 0; i < iterations; i++ {
+ c <- true
+ data += 1
+ <- c
+ }
+ wg.Wait()
+ if (data == iterations*(threads+1)) { fmt.Println("pass") }
+}`, []string{`pass`}},
+ // Test for https://github.com/golang/go/issues/37355
+ {"chanmm", "run", "", "atexit_sleep_ms=0", `
+package main
+import (
+ "sync"
+ "time"
+)
+func main() {
+ c := make(chan bool, 1)
+ var data uint64
+ var wg sync.WaitGroup
+ wg.Add(2)
+ c <- true
+ go func() {
+ defer wg.Done()
+ c <- true
+ }()
+ go func() {
+ defer wg.Done()
+ time.Sleep(time.Second)
+ <-c
+ data = 2
+ }()
+ data = 1
+ <-c
+ wg.Wait()
+ _ = data
+}
+`, []string{`==================
+WARNING: DATA RACE
+Write at 0x[0-9,a-f]+ by goroutine [0-9]:
+ main\.main\.func2\(\)
+ .*/main\.go:21 \+0x[0-9,a-f]+
+
+Previous write at 0x[0-9,a-f]+ by main goroutine:
+ main\.main\(\)
+ .*/main\.go:23 \+0x[0-9,a-f]+
+
+Goroutine [0-9] \(running\) created at:
+ main\.main\(\)
+ .*/main.go:[0-9]+ \+0x[0-9,a-f]+
+==================`}},
+}
diff --git a/src/runtime/race/race.go b/src/runtime/race/race.go
new file mode 100644
index 0000000..63fa83f
--- /dev/null
+++ b/src/runtime/race/race.go
@@ -0,0 +1,15 @@
+// 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.
+
+//go:build (race && linux && amd64) || (race && freebsd && amd64) || (race && netbsd && amd64) || (race && darwin && amd64) || (race && windows && amd64) || (race && linux && ppc64le) || (race && linux && arm64) || (race && darwin && arm64) || (race && openbsd && amd64)
+
+package race
+
+// This file merely ensures that we link in runtime/cgo in race build,
+// this in turn ensures that runtime uses pthread_create to create threads.
+// The prebuilt race runtime lives in race_GOOS_GOARCH.syso.
+// Calls to the runtime are done directly from src/runtime/race.go.
+
+// void __race_unused_func(void);
+import "C"
diff --git a/src/runtime/race/race_darwin_amd64.syso b/src/runtime/race/race_darwin_amd64.syso
new file mode 100644
index 0000000..6fbe140
--- /dev/null
+++ b/src/runtime/race/race_darwin_amd64.syso
Binary files differ
diff --git a/src/runtime/race/race_darwin_arm64.syso b/src/runtime/race/race_darwin_arm64.syso
new file mode 100644
index 0000000..207099e
--- /dev/null
+++ b/src/runtime/race/race_darwin_arm64.syso
Binary files differ
diff --git a/src/runtime/race/race_freebsd_amd64.syso b/src/runtime/race/race_freebsd_amd64.syso
new file mode 100644
index 0000000..2a5b46f
--- /dev/null
+++ b/src/runtime/race/race_freebsd_amd64.syso
Binary files differ
diff --git a/src/runtime/race/race_linux_amd64.syso b/src/runtime/race/race_linux_amd64.syso
new file mode 100644
index 0000000..e00398c
--- /dev/null
+++ b/src/runtime/race/race_linux_amd64.syso
Binary files differ
diff --git a/src/runtime/race/race_linux_arm64.syso b/src/runtime/race/race_linux_arm64.syso
new file mode 100644
index 0000000..9dae738
--- /dev/null
+++ b/src/runtime/race/race_linux_arm64.syso
Binary files differ
diff --git a/src/runtime/race/race_linux_ppc64le.syso b/src/runtime/race/race_linux_ppc64le.syso
new file mode 100644
index 0000000..b562656
--- /dev/null
+++ b/src/runtime/race/race_linux_ppc64le.syso
Binary files differ
diff --git a/src/runtime/race/race_linux_test.go b/src/runtime/race/race_linux_test.go
new file mode 100644
index 0000000..e8a2d0f
--- /dev/null
+++ b/src/runtime/race/race_linux_test.go
@@ -0,0 +1,37 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux && race
+
+package race_test
+
+import (
+ "sync/atomic"
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+func TestAtomicMmap(t *testing.T) {
+ // Test that atomic operations work on "external" memory. Previously they crashed (#16206).
+ // Also do a sanity correctness check: under race detector atomic operations
+ // are implemented inside of race runtime.
+ mem, err := syscall.Mmap(-1, 0, 1<<20, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+ if err != nil {
+ t.Fatalf("mmap failed: %v", err)
+ }
+ defer syscall.Munmap(mem)
+ a := (*uint64)(unsafe.Pointer(&mem[0]))
+ if *a != 0 {
+ t.Fatalf("bad atomic value: %v, want 0", *a)
+ }
+ atomic.AddUint64(a, 1)
+ if *a != 1 {
+ t.Fatalf("bad atomic value: %v, want 1", *a)
+ }
+ atomic.AddUint64(a, 1)
+ if *a != 2 {
+ t.Fatalf("bad atomic value: %v, want 2", *a)
+ }
+}
diff --git a/src/runtime/race/race_netbsd_amd64.syso b/src/runtime/race/race_netbsd_amd64.syso
new file mode 100644
index 0000000..11af16f
--- /dev/null
+++ b/src/runtime/race/race_netbsd_amd64.syso
Binary files differ
diff --git a/src/runtime/race/race_openbsd_amd64.syso b/src/runtime/race/race_openbsd_amd64.syso
new file mode 100644
index 0000000..9fefd87
--- /dev/null
+++ b/src/runtime/race/race_openbsd_amd64.syso
Binary files differ
diff --git a/src/runtime/race/race_test.go b/src/runtime/race/race_test.go
new file mode 100644
index 0000000..4fe6168
--- /dev/null
+++ b/src/runtime/race/race_test.go
@@ -0,0 +1,250 @@
+// 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.
+
+//go: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"
+ "internal/testenv"
+ "io"
+ "log"
+ "math/rand"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "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(t)
+ if err != nil {
+ t.Fatalf("Failed to run tests: %v\n%v", err, string(testOutput))
+ }
+ reader := bufio.NewReader(bytes.NewReader(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)
+ }
+ }
+
+ if totalTests == 0 {
+ t.Fatalf("failed to parse test output:\n%s", testOutput)
+ }
+ 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(t *testing.T) ([]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(testenv.GoToolPath(t), 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).
+ for _, env := range os.Environ() {
+ if strings.HasPrefix(env, "GOMAXPROCS=") ||
+ strings.HasPrefix(env, "GODEBUG=") ||
+ strings.HasPrefix(env, "GORACE=") {
+ continue
+ }
+ cmd.Env = append(cmd.Env, env)
+ }
+ // We set GOMAXPROCS=1 to prevent test flakiness.
+ // There are two sources of flakiness:
+ // 1. Some tests rely on particular execution order.
+ // If the order is different, race does not happen at all.
+ // 2. Ironically, ThreadSanitizer runtime contains a logical race condition
+ // that can lead to false negatives if racy accesses happen literally at the same time.
+ // Tests used to work reliably in the good old days of GOMAXPROCS=1.
+ // So let's set it for now. A more reliable solution is to explicitly annotate tests
+ // with required execution order by means of a special "invisible" synchronization primitive
+ // (that's what is done for C++ ThreadSanitizer tests). This is issue #14119.
+ cmd.Env = append(cmd.Env,
+ "GOMAXPROCS=1",
+ "GORACE=suppress_equal_stacks=0 suppress_equal_addresses=0",
+ )
+ // There are races: we expect tests to fail and the exit code to be non-zero.
+ out, _ := cmd.CombinedOutput()
+ if bytes.Contains(out, []byte("fatal error:")) {
+ // But don't expect runtime to crash.
+ return out, fmt.Errorf("runtime fatal error")
+ }
+ return out, nil
+}
+
+func TestIssue8102(t *testing.T) {
+ // If this compiles with -race, the test passes.
+ type S struct {
+ x any
+ i int
+ }
+ c := make(chan int)
+ a := [2]*int{}
+ for ; ; c <- *a[S{}.i] {
+ if t != nil {
+ break
+ }
+ }
+}
+
+func TestIssue9137(t *testing.T) {
+ a := []string{"a"}
+ i := 0
+ a[i], a[len(a)-1], a = a[len(a)-1], "", a[:len(a)-1]
+ if len(a) != 0 || a[:1][0] != "" {
+ t.Errorf("mangled a: %q %q", a, a[:1])
+ }
+}
+
+func BenchmarkSyncLeak(b *testing.B) {
+ const (
+ G = 1000
+ S = 1000
+ H = 10
+ )
+ var wg sync.WaitGroup
+ wg.Add(G)
+ for g := 0; g < G; g++ {
+ go func() {
+ defer wg.Done()
+ hold := make([][]uint32, H)
+ for i := 0; i < b.N; i++ {
+ a := make([]uint32, S)
+ atomic.AddUint32(&a[rand.Intn(len(a))], 1)
+ hold[rand.Intn(len(hold))] = a
+ }
+ _ = hold
+ }()
+ }
+ wg.Wait()
+}
+
+func BenchmarkStackLeak(b *testing.B) {
+ done := make(chan bool, 1)
+ for i := 0; i < b.N; i++ {
+ go func() {
+ growStack(rand.Intn(100))
+ done <- true
+ }()
+ <-done
+ }
+}
+
+func growStack(i int) {
+ if i == 0 {
+ return
+ }
+ growStack(i - 1)
+}
diff --git a/src/runtime/race/race_unix_test.go b/src/runtime/race/race_unix_test.go
new file mode 100644
index 0000000..6cc0730
--- /dev/null
+++ b/src/runtime/race/race_unix_test.go
@@ -0,0 +1,29 @@
+// Copyright 2014 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.
+
+//go:build race && (darwin || freebsd || linux)
+
+package race_test
+
+import (
+ "sync/atomic"
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+// Test that race detector does not crash when accessing non-Go allocated memory (issue 9136).
+func TestNonGoMemory(t *testing.T) {
+ data, err := syscall.Mmap(-1, 0, 4096, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+ if err != nil {
+ t.Fatalf("failed to mmap memory: %v", err)
+ }
+ p := (*uint32)(unsafe.Pointer(&data[0]))
+ atomic.AddUint32(p, 1)
+ (*p)++
+ if *p != 2 {
+ t.Fatalf("data[0] = %v, expect 2", *p)
+ }
+ syscall.Munmap(data)
+}
diff --git a/src/runtime/race/race_windows_amd64.syso b/src/runtime/race/race_windows_amd64.syso
new file mode 100644
index 0000000..9fbf9b4
--- /dev/null
+++ b/src/runtime/race/race_windows_amd64.syso
Binary files differ
diff --git a/src/runtime/race/race_windows_test.go b/src/runtime/race/race_windows_test.go
new file mode 100644
index 0000000..143b483
--- /dev/null
+++ b/src/runtime/race/race_windows_test.go
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build windows && race
+
+package race_test
+
+import (
+ "sync/atomic"
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+func TestAtomicMmap(t *testing.T) {
+ // Test that atomic operations work on "external" memory. Previously they crashed (#16206).
+ // Also do a sanity correctness check: under race detector atomic operations
+ // are implemented inside of race runtime.
+ kernel32 := syscall.NewLazyDLL("kernel32.dll")
+ VirtualAlloc := kernel32.NewProc("VirtualAlloc")
+ VirtualFree := kernel32.NewProc("VirtualFree")
+ const (
+ MEM_COMMIT = 0x00001000
+ MEM_RESERVE = 0x00002000
+ MEM_RELEASE = 0x8000
+ PAGE_READWRITE = 0x04
+ )
+ mem, _, err := syscall.Syscall6(VirtualAlloc.Addr(), 4, 0, 1<<20, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE, 0, 0)
+ if err != 0 {
+ t.Fatalf("VirtualAlloc failed: %v", err)
+ }
+ defer syscall.Syscall(VirtualFree.Addr(), 3, mem, 1<<20, MEM_RELEASE)
+ a := (*uint64)(unsafe.Pointer(mem))
+ if *a != 0 {
+ t.Fatalf("bad atomic value: %v, want 0", *a)
+ }
+ atomic.AddUint64(a, 1)
+ if *a != 1 {
+ t.Fatalf("bad atomic value: %v, want 1", *a)
+ }
+ atomic.AddUint64(a, 1)
+ if *a != 2 {
+ t.Fatalf("bad atomic value: %v, want 2", *a)
+ }
+}
diff --git a/src/runtime/race/sched_test.go b/src/runtime/race/sched_test.go
new file mode 100644
index 0000000..9fe83ea
--- /dev/null
+++ b/src/runtime/race/sched_test.go
@@ -0,0 +1,48 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build race
+
+package race_test
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "runtime"
+ "testing"
+)
+
+func TestRandomScheduling(t *testing.T) {
+ // Scheduler is most consistent with GOMAXPROCS=1.
+ // Use that to make the test most likely to fail.
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+ const N = 10
+ out := make([][]int, N)
+ for i := 0; i < N; i++ {
+ c := make(chan int, N)
+ for j := 0; j < N; j++ {
+ go func(j int) {
+ c <- j
+ }(j)
+ }
+ row := make([]int, N)
+ for j := 0; j < N; j++ {
+ row[j] = <-c
+ }
+ out[i] = row
+ }
+
+ for i := 0; i < N; i++ {
+ if !reflect.DeepEqual(out[0], out[i]) {
+ return // found a different order
+ }
+ }
+
+ var buf bytes.Buffer
+ for i := 0; i < N; i++ {
+ fmt.Fprintf(&buf, "%v\n", out[i])
+ }
+ t.Fatalf("consistent goroutine execution order:\n%v", buf.String())
+}
diff --git a/src/runtime/race/syso_test.go b/src/runtime/race/syso_test.go
new file mode 100644
index 0000000..2f1a91c
--- /dev/null
+++ b/src/runtime/race/syso_test.go
@@ -0,0 +1,33 @@
+// Copyright 2020 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.
+
+//go:build race
+
+package race
+
+import (
+ "bytes"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "testing"
+)
+
+func TestIssue37485(t *testing.T) {
+ files, err := filepath.Glob("./*.syso")
+ if err != nil {
+ t.Fatalf("can't find syso files: %s", err)
+ }
+ for _, f := range files {
+ cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), "tool", "nm", f)
+ res, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("nm of %s failed: %s", f, err)
+ continue
+ }
+ if bytes.Contains(res, []byte("getauxval")) {
+ t.Errorf("%s contains getauxval", f)
+ }
+ }
+}
diff --git a/src/runtime/race/testdata/atomic_test.go b/src/runtime/race/testdata/atomic_test.go
new file mode 100644
index 0000000..4ce7260
--- /dev/null
+++ b/src/runtime/race/testdata/atomic_test.go
@@ -0,0 +1,325 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "unsafe"
+)
+
+func TestNoRaceAtomicAddInt64(t *testing.T) {
+ var x1, x2 int8
+ _ = x1 + x2
+ var s int64
+ ch := make(chan bool, 2)
+ go func() {
+ x1 = 1
+ if atomic.AddInt64(&s, 1) == 2 {
+ x2 = 1
+ }
+ ch <- true
+ }()
+ go func() {
+ x2 = 1
+ if atomic.AddInt64(&s, 1) == 2 {
+ x1 = 1
+ }
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceAtomicAddInt64(t *testing.T) {
+ var x1, x2 int8
+ _ = x1 + x2
+ var s int64
+ ch := make(chan bool, 2)
+ go func() {
+ x1 = 1
+ if atomic.AddInt64(&s, 1) == 1 {
+ x2 = 1
+ }
+ ch <- true
+ }()
+ go func() {
+ x2 = 1
+ if atomic.AddInt64(&s, 1) == 1 {
+ x1 = 1
+ }
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRaceAtomicAddInt32(t *testing.T) {
+ var x1, x2 int8
+ _ = x1 + x2
+ var s int32
+ ch := make(chan bool, 2)
+ go func() {
+ x1 = 1
+ if atomic.AddInt32(&s, 1) == 2 {
+ x2 = 1
+ }
+ ch <- true
+ }()
+ go func() {
+ x2 = 1
+ if atomic.AddInt32(&s, 1) == 2 {
+ x1 = 1
+ }
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRaceAtomicLoadAddInt32(t *testing.T) {
+ var x int64
+ _ = x
+ var s int32
+ go func() {
+ x = 2
+ atomic.AddInt32(&s, 1)
+ }()
+ for atomic.LoadInt32(&s) != 1 {
+ runtime.Gosched()
+ }
+ x = 1
+}
+
+func TestNoRaceAtomicLoadStoreInt32(t *testing.T) {
+ var x int64
+ _ = x
+ var s int32
+ go func() {
+ x = 2
+ atomic.StoreInt32(&s, 1)
+ }()
+ for atomic.LoadInt32(&s) != 1 {
+ runtime.Gosched()
+ }
+ x = 1
+}
+
+func TestNoRaceAtomicStoreCASInt32(t *testing.T) {
+ var x int64
+ _ = x
+ var s int32
+ go func() {
+ x = 2
+ atomic.StoreInt32(&s, 1)
+ }()
+ for !atomic.CompareAndSwapInt32(&s, 1, 0) {
+ runtime.Gosched()
+ }
+ x = 1
+}
+
+func TestNoRaceAtomicCASLoadInt32(t *testing.T) {
+ var x int64
+ _ = x
+ var s int32
+ go func() {
+ x = 2
+ if !atomic.CompareAndSwapInt32(&s, 0, 1) {
+ panic("")
+ }
+ }()
+ for atomic.LoadInt32(&s) != 1 {
+ runtime.Gosched()
+ }
+ x = 1
+}
+
+func TestNoRaceAtomicCASCASInt32(t *testing.T) {
+ var x int64
+ _ = x
+ var s int32
+ go func() {
+ x = 2
+ if !atomic.CompareAndSwapInt32(&s, 0, 1) {
+ panic("")
+ }
+ }()
+ for !atomic.CompareAndSwapInt32(&s, 1, 0) {
+ runtime.Gosched()
+ }
+ x = 1
+}
+
+func TestNoRaceAtomicCASCASInt32_2(t *testing.T) {
+ var x1, x2 int8
+ _ = x1 + x2
+ var s int32
+ ch := make(chan bool, 2)
+ go func() {
+ x1 = 1
+ if !atomic.CompareAndSwapInt32(&s, 0, 1) {
+ x2 = 1
+ }
+ ch <- true
+ }()
+ go func() {
+ x2 = 1
+ if !atomic.CompareAndSwapInt32(&s, 0, 1) {
+ x1 = 1
+ }
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRaceAtomicLoadInt64(t *testing.T) {
+ var x int32
+ _ = x
+ var s int64
+ go func() {
+ x = 2
+ atomic.AddInt64(&s, 1)
+ }()
+ for atomic.LoadInt64(&s) != 1 {
+ runtime.Gosched()
+ }
+ x = 1
+}
+
+func TestNoRaceAtomicCASCASUInt64(t *testing.T) {
+ var x int64
+ _ = x
+ var s uint64
+ go func() {
+ x = 2
+ if !atomic.CompareAndSwapUint64(&s, 0, 1) {
+ panic("")
+ }
+ }()
+ for !atomic.CompareAndSwapUint64(&s, 1, 0) {
+ runtime.Gosched()
+ }
+ x = 1
+}
+
+func TestNoRaceAtomicLoadStorePointer(t *testing.T) {
+ var x int64
+ _ = x
+ var s unsafe.Pointer
+ var y int = 2
+ var p unsafe.Pointer = unsafe.Pointer(&y)
+ go func() {
+ x = 2
+ atomic.StorePointer(&s, p)
+ }()
+ for atomic.LoadPointer(&s) != p {
+ runtime.Gosched()
+ }
+ x = 1
+}
+
+func TestNoRaceAtomicStoreCASUint64(t *testing.T) {
+ var x int64
+ _ = x
+ var s uint64
+ go func() {
+ x = 2
+ atomic.StoreUint64(&s, 1)
+ }()
+ for !atomic.CompareAndSwapUint64(&s, 1, 0) {
+ runtime.Gosched()
+ }
+ x = 1
+}
+
+func TestRaceAtomicStoreLoad(t *testing.T) {
+ c := make(chan bool)
+ var a uint64
+ go func() {
+ atomic.StoreUint64(&a, 1)
+ c <- true
+ }()
+ _ = a
+ <-c
+}
+
+func TestRaceAtomicLoadStore(t *testing.T) {
+ c := make(chan bool)
+ var a uint64
+ go func() {
+ _ = atomic.LoadUint64(&a)
+ c <- true
+ }()
+ a = 1
+ <-c
+}
+
+func TestRaceAtomicAddLoad(t *testing.T) {
+ c := make(chan bool)
+ var a uint64
+ go func() {
+ atomic.AddUint64(&a, 1)
+ c <- true
+ }()
+ _ = a
+ <-c
+}
+
+func TestRaceAtomicAddStore(t *testing.T) {
+ c := make(chan bool)
+ var a uint64
+ go func() {
+ atomic.AddUint64(&a, 1)
+ c <- true
+ }()
+ a = 42
+ <-c
+}
+
+// A nil pointer in an atomic operation should not deadlock
+// the rest of the program. Used to hang indefinitely.
+func TestNoRaceAtomicCrash(t *testing.T) {
+ var mutex sync.Mutex
+ var nilptr *int32
+ panics := 0
+ defer func() {
+ if x := recover(); x != nil {
+ mutex.Lock()
+ panics++
+ mutex.Unlock()
+ } else {
+ panic("no panic")
+ }
+ }()
+ atomic.AddInt32(nilptr, 1)
+}
+
+func TestNoRaceDeferAtomicStore(t *testing.T) {
+ // Test that when an atomic function is deferred directly, the
+ // GC scans it correctly. See issue 42599.
+ type foo struct {
+ bar int64
+ }
+
+ var doFork func(f *foo, depth int)
+ doFork = func(f *foo, depth int) {
+ atomic.StoreInt64(&f.bar, 1)
+ defer atomic.StoreInt64(&f.bar, 0)
+ if depth > 0 {
+ for i := 0; i < 2; i++ {
+ f2 := &foo{}
+ go doFork(f2, depth-1)
+ }
+ }
+ runtime.GC()
+ }
+
+ f := &foo{}
+ doFork(f, 11)
+}
diff --git a/src/runtime/race/testdata/cgo_test.go b/src/runtime/race/testdata/cgo_test.go
new file mode 100644
index 0000000..211ef7d
--- /dev/null
+++ b/src/runtime/race/testdata/cgo_test.go
@@ -0,0 +1,21 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "internal/testenv"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+func TestNoRaceCgoSync(t *testing.T) {
+ cmd := exec.Command(testenv.GoToolPath(t), "run", "-race", "cgo_test_main.go")
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ t.Fatalf("program exited with error: %v\n", err)
+ }
+}
diff --git a/src/runtime/race/testdata/cgo_test_main.go b/src/runtime/race/testdata/cgo_test_main.go
new file mode 100644
index 0000000..620cea1
--- /dev/null
+++ b/src/runtime/race/testdata/cgo_test_main.go
@@ -0,0 +1,30 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+int sync;
+
+void Notify(void)
+{
+ __sync_fetch_and_add(&sync, 1);
+}
+
+void Wait(void)
+{
+ while(__sync_fetch_and_add(&sync, 0) == 0) {}
+}
+*/
+import "C"
+
+func main() {
+ data := 0
+ go func() {
+ data = 1
+ C.Notify()
+ }()
+ C.Wait()
+ _ = data
+}
diff --git a/src/runtime/race/testdata/chan_test.go b/src/runtime/race/testdata/chan_test.go
new file mode 100644
index 0000000..e39ad4f
--- /dev/null
+++ b/src/runtime/race/testdata/chan_test.go
@@ -0,0 +1,787 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "runtime"
+ "testing"
+ "time"
+)
+
+func TestNoRaceChanSync(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int)
+ go func() {
+ v = 1
+ c <- 0
+ }()
+ <-c
+ v = 2
+}
+
+func TestNoRaceChanSyncRev(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int)
+ go func() {
+ c <- 0
+ v = 2
+ }()
+ v = 1
+ <-c
+}
+
+func TestNoRaceChanAsync(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int, 10)
+ go func() {
+ v = 1
+ c <- 0
+ }()
+ <-c
+ v = 2
+}
+
+func TestRaceChanAsyncRev(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int, 10)
+ go func() {
+ c <- 0
+ v = 1
+ }()
+ v = 2
+ <-c
+}
+
+func TestNoRaceChanAsyncCloseRecv(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int, 10)
+ go func() {
+ v = 1
+ close(c)
+ }()
+ func() {
+ defer func() {
+ recover()
+ v = 2
+ }()
+ <-c
+ }()
+}
+
+func TestNoRaceChanAsyncCloseRecv2(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int, 10)
+ go func() {
+ v = 1
+ close(c)
+ }()
+ _, _ = <-c
+ v = 2
+}
+
+func TestNoRaceChanAsyncCloseRecv3(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int, 10)
+ go func() {
+ v = 1
+ close(c)
+ }()
+ for range c {
+ }
+ v = 2
+}
+
+func TestNoRaceChanSyncCloseRecv(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int)
+ go func() {
+ v = 1
+ close(c)
+ }()
+ func() {
+ defer func() {
+ recover()
+ v = 2
+ }()
+ <-c
+ }()
+}
+
+func TestNoRaceChanSyncCloseRecv2(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int)
+ go func() {
+ v = 1
+ close(c)
+ }()
+ _, _ = <-c
+ v = 2
+}
+
+func TestNoRaceChanSyncCloseRecv3(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int)
+ go func() {
+ v = 1
+ close(c)
+ }()
+ for range c {
+ }
+ v = 2
+}
+
+func TestRaceChanSyncCloseSend(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int)
+ go func() {
+ v = 1
+ close(c)
+ }()
+ func() {
+ defer func() {
+ recover()
+ }()
+ c <- 0
+ }()
+ v = 2
+}
+
+func TestRaceChanAsyncCloseSend(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int, 10)
+ go func() {
+ v = 1
+ close(c)
+ }()
+ func() {
+ defer func() {
+ recover()
+ }()
+ for {
+ c <- 0
+ }
+ }()
+ v = 2
+}
+
+func TestRaceChanCloseClose(t *testing.T) {
+ compl := make(chan bool, 2)
+ v1 := 0
+ v2 := 0
+ _ = v1 + v2
+ c := make(chan int)
+ go func() {
+ defer func() {
+ if recover() != nil {
+ v2 = 2
+ }
+ compl <- true
+ }()
+ v1 = 1
+ close(c)
+ }()
+ go func() {
+ defer func() {
+ if recover() != nil {
+ v1 = 2
+ }
+ compl <- true
+ }()
+ v2 = 1
+ close(c)
+ }()
+ <-compl
+ <-compl
+}
+
+func TestRaceChanSendLen(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int, 10)
+ go func() {
+ v = 1
+ c <- 1
+ }()
+ for len(c) == 0 {
+ runtime.Gosched()
+ }
+ v = 2
+}
+
+func TestRaceChanRecvLen(t *testing.T) {
+ v := 0
+ _ = v
+ c := make(chan int, 10)
+ c <- 1
+ go func() {
+ v = 1
+ <-c
+ }()
+ for len(c) != 0 {
+ runtime.Gosched()
+ }
+ v = 2
+}
+
+func TestRaceChanSendSend(t *testing.T) {
+ compl := make(chan bool, 2)
+ v1 := 0
+ v2 := 0
+ _ = v1 + v2
+ c := make(chan int, 1)
+ go func() {
+ v1 = 1
+ select {
+ case c <- 1:
+ default:
+ v2 = 2
+ }
+ compl <- true
+ }()
+ go func() {
+ v2 = 1
+ select {
+ case c <- 1:
+ default:
+ v1 = 2
+ }
+ compl <- true
+ }()
+ <-compl
+ <-compl
+}
+
+func TestNoRaceChanPtr(t *testing.T) {
+ type msg struct {
+ x int
+ }
+ c := make(chan *msg)
+ go func() {
+ c <- &msg{1}
+ }()
+ m := <-c
+ m.x = 2
+}
+
+func TestRaceChanWrongSend(t *testing.T) {
+ v1 := 0
+ v2 := 0
+ _ = v1 + v2
+ c := make(chan int, 2)
+ go func() {
+ v1 = 1
+ c <- 1
+ }()
+ go func() {
+ v2 = 2
+ c <- 2
+ }()
+ time.Sleep(1e7)
+ if <-c == 1 {
+ v2 = 3
+ } else {
+ v1 = 3
+ }
+}
+
+func TestRaceChanWrongClose(t *testing.T) {
+ v1 := 0
+ v2 := 0
+ _ = v1 + v2
+ c := make(chan int, 1)
+ done := make(chan bool)
+ go func() {
+ defer func() {
+ recover()
+ }()
+ v1 = 1
+ c <- 1
+ done <- true
+ }()
+ go func() {
+ time.Sleep(1e7)
+ v2 = 2
+ close(c)
+ done <- true
+ }()
+ time.Sleep(2e7)
+ if _, who := <-c; who {
+ v2 = 2
+ } else {
+ v1 = 2
+ }
+ <-done
+ <-done
+}
+
+func TestRaceChanSendClose(t *testing.T) {
+ compl := make(chan bool, 2)
+ c := make(chan int, 1)
+ go func() {
+ defer func() {
+ recover()
+ compl <- true
+ }()
+ c <- 1
+ }()
+ go func() {
+ time.Sleep(10 * time.Millisecond)
+ close(c)
+ compl <- true
+ }()
+ <-compl
+ <-compl
+}
+
+func TestRaceChanSendSelectClose(t *testing.T) {
+ compl := make(chan bool, 2)
+ c := make(chan int, 1)
+ c1 := make(chan int)
+ go func() {
+ defer func() {
+ recover()
+ compl <- true
+ }()
+ time.Sleep(10 * time.Millisecond)
+ select {
+ case c <- 1:
+ case <-c1:
+ }
+ }()
+ go func() {
+ close(c)
+ compl <- true
+ }()
+ <-compl
+ <-compl
+}
+
+func TestRaceSelectReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ c1 := make(chan int, 10)
+ c2 := make(chan int, 10)
+ c3 := make(chan int)
+ c2 <- 1
+ go func() {
+ select {
+ case c1 <- x: // read of x races with...
+ case c3 <- 1:
+ }
+ done <- true
+ }()
+ select {
+ case x = <-c2: // ... write to x here
+ case c3 <- 1:
+ }
+ <-done
+}
+
+func TestRaceSelectReadWriteSync(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ c1 := make(chan int)
+ c2 := make(chan int)
+ c3 := make(chan int)
+ // make c1 and c2 ready for communication
+ go func() {
+ <-c1
+ }()
+ go func() {
+ c2 <- 1
+ }()
+ go func() {
+ select {
+ case c1 <- x: // read of x races with...
+ case c3 <- 1:
+ }
+ done <- true
+ }()
+ select {
+ case x = <-c2: // ... write to x here
+ case c3 <- 1:
+ }
+ <-done
+}
+
+func TestNoRaceSelectReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ c1 := make(chan int)
+ c2 := make(chan int)
+ go func() {
+ select {
+ case c1 <- x: // read of x does not race with...
+ case c2 <- 1:
+ }
+ done <- true
+ }()
+ select {
+ case x = <-c1: // ... write to x here
+ case c2 <- 1:
+ }
+ <-done
+}
+
+func TestRaceChanReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ c1 := make(chan int, 10)
+ c2 := make(chan int, 10)
+ c2 <- 10
+ x := 0
+ go func() {
+ c1 <- x // read of x races with...
+ done <- true
+ }()
+ x = <-c2 // ... write to x here
+ <-done
+}
+
+func TestRaceChanReadWriteSync(t *testing.T) {
+ done := make(chan bool)
+ c1 := make(chan int)
+ c2 := make(chan int)
+ // make c1 and c2 ready for communication
+ go func() {
+ <-c1
+ }()
+ go func() {
+ c2 <- 10
+ }()
+ x := 0
+ go func() {
+ c1 <- x // read of x races with...
+ done <- true
+ }()
+ x = <-c2 // ... write to x here
+ <-done
+}
+
+func TestNoRaceChanReadWriteAsync(t *testing.T) {
+ done := make(chan bool)
+ c1 := make(chan int, 10)
+ x := 0
+ go func() {
+ c1 <- x // read of x does not race with...
+ done <- true
+ }()
+ x = <-c1 // ... write to x here
+ <-done
+}
+
+func TestNoRaceProducerConsumerUnbuffered(t *testing.T) {
+ type Task struct {
+ f func()
+ done chan bool
+ }
+
+ queue := make(chan Task)
+
+ go func() {
+ t := <-queue
+ t.f()
+ t.done <- true
+ }()
+
+ doit := func(f func()) {
+ done := make(chan bool, 1)
+ queue <- Task{f, done}
+ <-done
+ }
+
+ x := 0
+ doit(func() {
+ x = 1
+ })
+ _ = x
+}
+
+func TestRaceChanItselfSend(t *testing.T) {
+ compl := make(chan bool, 1)
+ c := make(chan int, 10)
+ go func() {
+ c <- 0
+ compl <- true
+ }()
+ c = make(chan int, 20)
+ <-compl
+}
+
+func TestRaceChanItselfRecv(t *testing.T) {
+ compl := make(chan bool, 1)
+ c := make(chan int, 10)
+ c <- 1
+ go func() {
+ <-c
+ compl <- true
+ }()
+ time.Sleep(1e7)
+ c = make(chan int, 20)
+ <-compl
+}
+
+func TestRaceChanItselfNil(t *testing.T) {
+ c := make(chan int, 10)
+ go func() {
+ c <- 0
+ }()
+ time.Sleep(1e7)
+ c = nil
+ _ = c
+}
+
+func TestRaceChanItselfClose(t *testing.T) {
+ compl := make(chan bool, 1)
+ c := make(chan int)
+ go func() {
+ close(c)
+ compl <- true
+ }()
+ c = make(chan int)
+ <-compl
+}
+
+func TestRaceChanItselfLen(t *testing.T) {
+ compl := make(chan bool, 1)
+ c := make(chan int)
+ go func() {
+ _ = len(c)
+ compl <- true
+ }()
+ c = make(chan int)
+ <-compl
+}
+
+func TestRaceChanItselfCap(t *testing.T) {
+ compl := make(chan bool, 1)
+ c := make(chan int)
+ go func() {
+ _ = cap(c)
+ compl <- true
+ }()
+ c = make(chan int)
+ <-compl
+}
+
+func TestNoRaceChanCloseLen(t *testing.T) {
+ c := make(chan int, 10)
+ r := make(chan int, 10)
+ go func() {
+ r <- len(c)
+ }()
+ go func() {
+ close(c)
+ r <- 0
+ }()
+ <-r
+ <-r
+}
+
+func TestNoRaceChanCloseCap(t *testing.T) {
+ c := make(chan int, 10)
+ r := make(chan int, 10)
+ go func() {
+ r <- cap(c)
+ }()
+ go func() {
+ close(c)
+ r <- 0
+ }()
+ <-r
+ <-r
+}
+
+func TestRaceChanCloseSend(t *testing.T) {
+ compl := make(chan bool, 1)
+ c := make(chan int, 10)
+ go func() {
+ close(c)
+ compl <- true
+ }()
+ c <- 0
+ <-compl
+}
+
+func TestNoRaceChanMutex(t *testing.T) {
+ done := make(chan struct{})
+ mtx := make(chan struct{}, 1)
+ data := 0
+ _ = data
+ go func() {
+ mtx <- struct{}{}
+ data = 42
+ <-mtx
+ done <- struct{}{}
+ }()
+ mtx <- struct{}{}
+ data = 43
+ <-mtx
+ <-done
+}
+
+func TestNoRaceSelectMutex(t *testing.T) {
+ done := make(chan struct{})
+ mtx := make(chan struct{}, 1)
+ aux := make(chan bool)
+ data := 0
+ _ = data
+ go func() {
+ select {
+ case mtx <- struct{}{}:
+ case <-aux:
+ }
+ data = 42
+ select {
+ case <-mtx:
+ case <-aux:
+ }
+ done <- struct{}{}
+ }()
+ select {
+ case mtx <- struct{}{}:
+ case <-aux:
+ }
+ data = 43
+ select {
+ case <-mtx:
+ case <-aux:
+ }
+ <-done
+}
+
+func TestRaceChanSem(t *testing.T) {
+ done := make(chan struct{})
+ mtx := make(chan bool, 2)
+ data := 0
+ _ = data
+ go func() {
+ mtx <- true
+ data = 42
+ <-mtx
+ done <- struct{}{}
+ }()
+ mtx <- true
+ data = 43
+ <-mtx
+ <-done
+}
+
+func TestNoRaceChanWaitGroup(t *testing.T) {
+ const N = 10
+ chanWg := make(chan bool, N/2)
+ data := make([]int, N)
+ for i := 0; i < N; i++ {
+ chanWg <- true
+ go func(i int) {
+ data[i] = 42
+ <-chanWg
+ }(i)
+ }
+ for i := 0; i < cap(chanWg); i++ {
+ chanWg <- true
+ }
+ for i := 0; i < N; i++ {
+ _ = data[i]
+ }
+}
+
+// Test that sender synchronizes with receiver even if the sender was blocked.
+func TestNoRaceBlockedSendSync(t *testing.T) {
+ c := make(chan *int, 1)
+ c <- nil
+ go func() {
+ i := 42
+ c <- &i
+ }()
+ // Give the sender time to actually block.
+ // This sleep is completely optional: race report must not be printed
+ // regardless of whether the sender actually blocks or not.
+ // It cannot lead to flakiness.
+ time.Sleep(10 * time.Millisecond)
+ <-c
+ p := <-c
+ if *p != 42 {
+ t.Fatal()
+ }
+}
+
+// The same as TestNoRaceBlockedSendSync above, but sender unblock happens in a select.
+func TestNoRaceBlockedSelectSendSync(t *testing.T) {
+ c := make(chan *int, 1)
+ c <- nil
+ go func() {
+ i := 42
+ c <- &i
+ }()
+ time.Sleep(10 * time.Millisecond)
+ <-c
+ select {
+ case p := <-c:
+ if *p != 42 {
+ t.Fatal()
+ }
+ case <-make(chan int):
+ }
+}
+
+// Test that close synchronizes with a read from the empty closed channel.
+// See https://golang.org/issue/36714.
+func TestNoRaceCloseHappensBeforeRead(t *testing.T) {
+ for i := 0; i < 100; i++ {
+ var loc int
+ var write = make(chan struct{})
+ var read = make(chan struct{})
+
+ go func() {
+ select {
+ case <-write:
+ _ = loc
+ default:
+ }
+ close(read)
+ }()
+
+ go func() {
+ loc = 1
+ close(write)
+ }()
+
+ <-read
+ }
+}
+
+// Test that we call the proper race detector function when c.elemsize==0.
+// See https://github.com/golang/go/issues/42598
+func TestNoRaceElemetSize0(t *testing.T) {
+ var x, y int
+ var c = make(chan struct{}, 2)
+ c <- struct{}{}
+ c <- struct{}{}
+ go func() {
+ x += 1
+ <-c
+ }()
+ go func() {
+ y += 1
+ <-c
+ }()
+ time.Sleep(10 * time.Millisecond)
+ c <- struct{}{}
+ c <- struct{}{}
+ x += 1
+ y += 1
+}
diff --git a/src/runtime/race/testdata/comp_test.go b/src/runtime/race/testdata/comp_test.go
new file mode 100644
index 0000000..27b2d00
--- /dev/null
+++ b/src/runtime/race/testdata/comp_test.go
@@ -0,0 +1,186 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "testing"
+)
+
+type P struct {
+ x, y int
+}
+
+type S struct {
+ s1, s2 P
+}
+
+func TestNoRaceComp(t *testing.T) {
+ c := make(chan bool, 1)
+ var s S
+ go func() {
+ s.s2.x = 1
+ c <- true
+ }()
+ s.s2.y = 2
+ <-c
+}
+
+func TestNoRaceComp2(t *testing.T) {
+ c := make(chan bool, 1)
+ var s S
+ go func() {
+ s.s1.x = 1
+ c <- true
+ }()
+ s.s1.y = 2
+ <-c
+}
+
+func TestRaceComp(t *testing.T) {
+ c := make(chan bool, 1)
+ var s S
+ go func() {
+ s.s2.y = 1
+ c <- true
+ }()
+ s.s2.y = 2
+ <-c
+}
+
+func TestRaceComp2(t *testing.T) {
+ c := make(chan bool, 1)
+ var s S
+ go func() {
+ s.s1.x = 1
+ c <- true
+ }()
+ s = S{}
+ <-c
+}
+
+func TestRaceComp3(t *testing.T) {
+ c := make(chan bool, 1)
+ var s S
+ go func() {
+ s.s2.y = 1
+ c <- true
+ }()
+ s = S{}
+ <-c
+}
+
+func TestRaceCompArray(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]S, 10)
+ x := 4
+ go func() {
+ s[x].s2.y = 1
+ c <- true
+ }()
+ x = 5
+ <-c
+}
+
+type P2 P
+type S2 S
+
+func TestRaceConv1(t *testing.T) {
+ c := make(chan bool, 1)
+ var p P2
+ go func() {
+ p.x = 1
+ c <- true
+ }()
+ _ = P(p).x
+ <-c
+}
+
+func TestRaceConv2(t *testing.T) {
+ c := make(chan bool, 1)
+ var p P2
+ go func() {
+ p.x = 1
+ c <- true
+ }()
+ ptr := &p
+ _ = P(*ptr).x
+ <-c
+}
+
+func TestRaceConv3(t *testing.T) {
+ c := make(chan bool, 1)
+ var s S2
+ go func() {
+ s.s1.x = 1
+ c <- true
+ }()
+ _ = P2(S(s).s1).x
+ <-c
+}
+
+type X struct {
+ V [4]P
+}
+
+type X2 X
+
+func TestRaceConv4(t *testing.T) {
+ c := make(chan bool, 1)
+ var x X2
+ go func() {
+ x.V[1].x = 1
+ c <- true
+ }()
+ _ = P2(X(x).V[1]).x
+ <-c
+}
+
+type Ptr struct {
+ s1, s2 *P
+}
+
+func TestNoRaceCompPtr(t *testing.T) {
+ c := make(chan bool, 1)
+ p := Ptr{&P{}, &P{}}
+ go func() {
+ p.s1.x = 1
+ c <- true
+ }()
+ p.s1.y = 2
+ <-c
+}
+
+func TestNoRaceCompPtr2(t *testing.T) {
+ c := make(chan bool, 1)
+ p := Ptr{&P{}, &P{}}
+ go func() {
+ p.s1.x = 1
+ c <- true
+ }()
+ _ = p
+ <-c
+}
+
+func TestRaceCompPtr(t *testing.T) {
+ c := make(chan bool, 1)
+ p := Ptr{&P{}, &P{}}
+ go func() {
+ p.s2.x = 1
+ c <- true
+ }()
+ p.s2.x = 2
+ <-c
+}
+
+func TestRaceCompPtr2(t *testing.T) {
+ c := make(chan bool, 1)
+ p := Ptr{&P{}, &P{}}
+ go func() {
+ p.s2.x = 1
+ c <- true
+ }()
+ p.s2 = &P{}
+ <-c
+}
diff --git a/src/runtime/race/testdata/finalizer_test.go b/src/runtime/race/testdata/finalizer_test.go
new file mode 100644
index 0000000..3ac33d2
--- /dev/null
+++ b/src/runtime/race/testdata/finalizer_test.go
@@ -0,0 +1,68 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "runtime"
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestNoRaceFin(t *testing.T) {
+ c := make(chan bool)
+ go func() {
+ x := new(string)
+ runtime.SetFinalizer(x, func(x *string) {
+ *x = "foo"
+ })
+ *x = "bar"
+ c <- true
+ }()
+ <-c
+ runtime.GC()
+ time.Sleep(100 * time.Millisecond)
+}
+
+var finVar struct {
+ sync.Mutex
+ cnt int
+}
+
+func TestNoRaceFinGlobal(t *testing.T) {
+ c := make(chan bool)
+ go func() {
+ x := new(string)
+ runtime.SetFinalizer(x, func(x *string) {
+ finVar.Lock()
+ finVar.cnt++
+ finVar.Unlock()
+ })
+ c <- true
+ }()
+ <-c
+ runtime.GC()
+ time.Sleep(100 * time.Millisecond)
+ finVar.Lock()
+ finVar.cnt++
+ finVar.Unlock()
+}
+
+func TestRaceFin(t *testing.T) {
+ c := make(chan bool)
+ y := 0
+ _ = y
+ go func() {
+ x := new(string)
+ runtime.SetFinalizer(x, func(x *string) {
+ y = 42
+ })
+ c <- true
+ }()
+ <-c
+ runtime.GC()
+ time.Sleep(100 * time.Millisecond)
+ y = 66
+}
diff --git a/src/runtime/race/testdata/io_test.go b/src/runtime/race/testdata/io_test.go
new file mode 100644
index 0000000..3303cb0
--- /dev/null
+++ b/src/runtime/race/testdata/io_test.go
@@ -0,0 +1,75 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "fmt"
+ "net"
+ "net/http"
+ "os"
+ "path/filepath"
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestNoRaceIOFile(t *testing.T) {
+ x := 0
+ path := t.TempDir()
+ fname := filepath.Join(path, "data")
+ go func() {
+ x = 42
+ f, _ := os.Create(fname)
+ f.Write([]byte("done"))
+ f.Close()
+ }()
+ for {
+ f, err := os.Open(fname)
+ if err != nil {
+ time.Sleep(1e6)
+ continue
+ }
+ buf := make([]byte, 100)
+ count, err := f.Read(buf)
+ if count == 0 {
+ time.Sleep(1e6)
+ continue
+ }
+ break
+ }
+ _ = x
+}
+
+var (
+ regHandler sync.Once
+ handlerData int
+)
+
+func TestNoRaceIOHttp(t *testing.T) {
+ regHandler.Do(func() {
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ handlerData++
+ fmt.Fprintf(w, "test")
+ handlerData++
+ })
+ })
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("net.Listen: %v", err)
+ }
+ defer ln.Close()
+ go http.Serve(ln, nil)
+ handlerData++
+ _, err = http.Get("http://" + ln.Addr().String())
+ if err != nil {
+ t.Fatalf("http.Get: %v", err)
+ }
+ handlerData++
+ _, err = http.Get("http://" + ln.Addr().String())
+ if err != nil {
+ t.Fatalf("http.Get: %v", err)
+ }
+ handlerData++
+}
diff --git a/src/runtime/race/testdata/issue12225_test.go b/src/runtime/race/testdata/issue12225_test.go
new file mode 100644
index 0000000..0494493
--- /dev/null
+++ b/src/runtime/race/testdata/issue12225_test.go
@@ -0,0 +1,20 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import "unsafe"
+
+// golang.org/issue/12225
+// The test is that this compiles at all.
+
+//go:noinline
+func convert(s string) []byte {
+ return []byte(s)
+}
+
+func issue12225() {
+ println(*(*int)(unsafe.Pointer(&convert("")[0])))
+ println(*(*int)(unsafe.Pointer(&[]byte("")[0])))
+}
diff --git a/src/runtime/race/testdata/issue12664_test.go b/src/runtime/race/testdata/issue12664_test.go
new file mode 100644
index 0000000..714e83d
--- /dev/null
+++ b/src/runtime/race/testdata/issue12664_test.go
@@ -0,0 +1,76 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "fmt"
+ "testing"
+)
+
+var issue12664 = "hi"
+
+func TestRaceIssue12664(t *testing.T) {
+ c := make(chan struct{})
+ go func() {
+ issue12664 = "bye"
+ close(c)
+ }()
+ fmt.Println(issue12664)
+ <-c
+}
+
+type MyI interface {
+ foo()
+}
+
+type MyT int
+
+func (MyT) foo() {
+}
+
+var issue12664_2 MyT = 0
+
+func TestRaceIssue12664_2(t *testing.T) {
+ c := make(chan struct{})
+ go func() {
+ issue12664_2 = 1
+ close(c)
+ }()
+ func(x MyI) {
+ // Never true, but prevents inlining.
+ if x.(MyT) == -1 {
+ close(c)
+ }
+ }(issue12664_2)
+ <-c
+}
+
+var issue12664_3 MyT = 0
+
+func TestRaceIssue12664_3(t *testing.T) {
+ c := make(chan struct{})
+ go func() {
+ issue12664_3 = 1
+ close(c)
+ }()
+ var r MyT
+ var i any = r
+ issue12664_3 = i.(MyT)
+ <-c
+}
+
+var issue12664_4 MyT = 0
+
+func TestRaceIssue12664_4(t *testing.T) {
+ c := make(chan struct{})
+ go func() {
+ issue12664_4 = 1
+ close(c)
+ }()
+ var r MyT
+ var i MyI = r
+ issue12664_4 = i.(MyT)
+ <-c
+}
diff --git a/src/runtime/race/testdata/issue13264_test.go b/src/runtime/race/testdata/issue13264_test.go
new file mode 100644
index 0000000..d42290d
--- /dev/null
+++ b/src/runtime/race/testdata/issue13264_test.go
@@ -0,0 +1,13 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+// golang.org/issue/13264
+// The test is that this compiles at all.
+
+func issue13264() {
+ for ; ; []map[int]int{}[0][0] = 0 {
+ }
+}
diff --git a/src/runtime/race/testdata/map_test.go b/src/runtime/race/testdata/map_test.go
new file mode 100644
index 0000000..88e735e
--- /dev/null
+++ b/src/runtime/race/testdata/map_test.go
@@ -0,0 +1,335 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "testing"
+)
+
+func TestRaceMapRW(t *testing.T) {
+ m := make(map[int]int)
+ ch := make(chan bool, 1)
+ go func() {
+ _ = m[1]
+ ch <- true
+ }()
+ m[1] = 1
+ <-ch
+}
+
+func TestRaceMapRW2(t *testing.T) {
+ m := make(map[int]int)
+ ch := make(chan bool, 1)
+ go func() {
+ _, _ = m[1]
+ ch <- true
+ }()
+ m[1] = 1
+ <-ch
+}
+
+func TestRaceMapRWArray(t *testing.T) {
+ // Check instrumentation of unaddressable arrays (issue 4578).
+ m := make(map[int][2]int)
+ ch := make(chan bool, 1)
+ go func() {
+ _ = m[1][1]
+ ch <- true
+ }()
+ m[2] = [2]int{1, 2}
+ <-ch
+}
+
+func TestNoRaceMapRR(t *testing.T) {
+ m := make(map[int]int)
+ ch := make(chan bool, 1)
+ go func() {
+ _, _ = m[1]
+ ch <- true
+ }()
+ _ = m[1]
+ <-ch
+}
+
+func TestRaceMapRange(t *testing.T) {
+ m := make(map[int]int)
+ ch := make(chan bool, 1)
+ go func() {
+ for range m {
+ }
+ ch <- true
+ }()
+ m[1] = 1
+ <-ch
+}
+
+func TestRaceMapRange2(t *testing.T) {
+ m := make(map[int]int)
+ ch := make(chan bool, 1)
+ go func() {
+ for range m {
+ }
+ ch <- true
+ }()
+ m[1] = 1
+ <-ch
+}
+
+func TestNoRaceMapRangeRange(t *testing.T) {
+ m := make(map[int]int)
+ // now the map is not empty and range triggers an event
+ // should work without this (as in other tests)
+ // so it is suspicious if this test passes and others don't
+ m[0] = 0
+ ch := make(chan bool, 1)
+ go func() {
+ for range m {
+ }
+ ch <- true
+ }()
+ for range m {
+ }
+ <-ch
+}
+
+func TestRaceMapLen(t *testing.T) {
+ m := make(map[string]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ _ = len(m)
+ ch <- true
+ }()
+ m[""] = true
+ <-ch
+}
+
+func TestRaceMapDelete(t *testing.T) {
+ m := make(map[string]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ delete(m, "")
+ ch <- true
+ }()
+ m[""] = true
+ <-ch
+}
+
+func TestRaceMapLenDelete(t *testing.T) {
+ m := make(map[string]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ delete(m, "a")
+ ch <- true
+ }()
+ _ = len(m)
+ <-ch
+}
+
+func TestRaceMapVariable(t *testing.T) {
+ ch := make(chan bool, 1)
+ m := make(map[int]int)
+ _ = m
+ go func() {
+ m = make(map[int]int)
+ ch <- true
+ }()
+ m = make(map[int]int)
+ <-ch
+}
+
+func TestRaceMapVariable2(t *testing.T) {
+ ch := make(chan bool, 1)
+ m := make(map[int]int)
+ go func() {
+ m[1] = 1
+ ch <- true
+ }()
+ m = make(map[int]int)
+ <-ch
+}
+
+func TestRaceMapVariable3(t *testing.T) {
+ ch := make(chan bool, 1)
+ m := make(map[int]int)
+ go func() {
+ _ = m[1]
+ ch <- true
+ }()
+ m = make(map[int]int)
+ <-ch
+}
+
+type Big struct {
+ x [17]int32
+}
+
+func TestRaceMapLookupPartKey(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ _ = m[*k]
+ <-ch
+}
+
+func TestRaceMapLookupPartKey2(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ _, _ = m[*k]
+ <-ch
+}
+func TestRaceMapDeletePartKey(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ delete(m, *k)
+ <-ch
+}
+
+func TestRaceMapInsertPartKey(t *testing.T) {
+ k := &Big{}
+ m := make(map[Big]bool)
+ ch := make(chan bool, 1)
+ go func() {
+ k.x[8] = 1
+ ch <- true
+ }()
+ m[*k] = true
+ <-ch
+}
+
+func TestRaceMapInsertPartVal(t *testing.T) {
+ v := &Big{}
+ m := make(map[int]Big)
+ ch := make(chan bool, 1)
+ go func() {
+ v.x[8] = 1
+ ch <- true
+ }()
+ m[1] = *v
+ <-ch
+}
+
+// Test for issue 7561.
+func TestRaceMapAssignMultipleReturn(t *testing.T) {
+ connect := func() (int, error) { return 42, nil }
+ conns := make(map[int][]int)
+ conns[1] = []int{0}
+ ch := make(chan bool, 1)
+ var err error
+ _ = err
+ go func() {
+ conns[1][0], err = connect()
+ ch <- true
+ }()
+ x := conns[1][0]
+ _ = x
+ <-ch
+}
+
+// BigKey and BigVal must be larger than 256 bytes,
+// so that compiler sets KindGCProg for them.
+type BigKey [1000]*int
+
+type BigVal struct {
+ x int
+ y [1000]*int
+}
+
+func TestRaceMapBigKeyAccess1(t *testing.T) {
+ m := make(map[BigKey]int)
+ var k BigKey
+ ch := make(chan bool, 1)
+ go func() {
+ _ = m[k]
+ ch <- true
+ }()
+ k[30] = new(int)
+ <-ch
+}
+
+func TestRaceMapBigKeyAccess2(t *testing.T) {
+ m := make(map[BigKey]int)
+ var k BigKey
+ ch := make(chan bool, 1)
+ go func() {
+ _, _ = m[k]
+ ch <- true
+ }()
+ k[30] = new(int)
+ <-ch
+}
+
+func TestRaceMapBigKeyInsert(t *testing.T) {
+ m := make(map[BigKey]int)
+ var k BigKey
+ ch := make(chan bool, 1)
+ go func() {
+ m[k] = 1
+ ch <- true
+ }()
+ k[30] = new(int)
+ <-ch
+}
+
+func TestRaceMapBigKeyDelete(t *testing.T) {
+ m := make(map[BigKey]int)
+ var k BigKey
+ ch := make(chan bool, 1)
+ go func() {
+ delete(m, k)
+ ch <- true
+ }()
+ k[30] = new(int)
+ <-ch
+}
+
+func TestRaceMapBigValInsert(t *testing.T) {
+ m := make(map[int]BigVal)
+ var v BigVal
+ ch := make(chan bool, 1)
+ go func() {
+ m[1] = v
+ ch <- true
+ }()
+ v.y[30] = new(int)
+ <-ch
+}
+
+func TestRaceMapBigValAccess1(t *testing.T) {
+ m := make(map[int]BigVal)
+ var v BigVal
+ ch := make(chan bool, 1)
+ go func() {
+ v = m[1]
+ ch <- true
+ }()
+ v.y[30] = new(int)
+ <-ch
+}
+
+func TestRaceMapBigValAccess2(t *testing.T) {
+ m := make(map[int]BigVal)
+ var v BigVal
+ ch := make(chan bool, 1)
+ go func() {
+ v, _ = m[1]
+ ch <- true
+ }()
+ v.y[30] = new(int)
+ <-ch
+}
diff --git a/src/runtime/race/testdata/mop_test.go b/src/runtime/race/testdata/mop_test.go
new file mode 100644
index 0000000..2d09373
--- /dev/null
+++ b/src/runtime/race/testdata/mop_test.go
@@ -0,0 +1,2082 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "runtime"
+ "sync"
+ "testing"
+ "time"
+ "unsafe"
+)
+
+type Point struct {
+ x, y int
+}
+
+type NamedPoint struct {
+ name string
+ p Point
+}
+
+type DummyWriter struct {
+ state int
+}
+type Writer interface {
+ Write(p []byte) (n int)
+}
+
+func (d DummyWriter) Write(p []byte) (n int) {
+ return 0
+}
+
+var GlobalX, GlobalY int = 0, 0
+var GlobalCh chan int = make(chan int, 2)
+
+func GlobalFunc1() {
+ GlobalY = GlobalX
+ GlobalCh <- 1
+}
+
+func GlobalFunc2() {
+ GlobalX = 1
+ GlobalCh <- 1
+}
+
+func TestRaceIntRWGlobalFuncs(t *testing.T) {
+ go GlobalFunc1()
+ go GlobalFunc2()
+ <-GlobalCh
+ <-GlobalCh
+}
+
+func TestRaceIntRWClosures(t *testing.T) {
+ var x, y int
+ _ = y
+ ch := make(chan int, 2)
+
+ go func() {
+ y = x
+ ch <- 1
+ }()
+ go func() {
+ x = 1
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRaceIntRWClosures(t *testing.T) {
+ var x, y int
+ _ = y
+ ch := make(chan int, 1)
+
+ go func() {
+ y = x
+ ch <- 1
+ }()
+ <-ch
+ go func() {
+ x = 1
+ ch <- 1
+ }()
+ <-ch
+
+}
+
+func TestRaceInt32RWClosures(t *testing.T) {
+ var x, y int32
+ _ = y
+ ch := make(chan bool, 2)
+
+ go func() {
+ y = x
+ ch <- true
+ }()
+ go func() {
+ x = 1
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRaceCase(t *testing.T) {
+ var y int
+ for x := -1; x <= 1; x++ {
+ switch {
+ case x < 0:
+ y = -1
+ case x == 0:
+ y = 0
+ case x > 0:
+ y = 1
+ }
+ }
+ y++
+}
+
+func TestRaceCaseCondition(t *testing.T) {
+ var x int = 0
+ ch := make(chan int, 2)
+
+ go func() {
+ x = 2
+ ch <- 1
+ }()
+ go func() {
+ switch x < 2 {
+ case true:
+ x = 1
+ //case false:
+ // x = 5
+ }
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceCaseCondition2(t *testing.T) {
+ // switch body is rearranged by the compiler so the tests
+ // passes even if we don't instrument '<'
+ var x int = 0
+ ch := make(chan int, 2)
+
+ go func() {
+ x = 2
+ ch <- 1
+ }()
+ go func() {
+ switch x < 2 {
+ case true:
+ x = 1
+ case false:
+ x = 5
+ }
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceCaseBody(t *testing.T) {
+ var x, y int
+ _ = y
+ ch := make(chan int, 2)
+
+ go func() {
+ y = x
+ ch <- 1
+ }()
+ go func() {
+ switch {
+ default:
+ x = 1
+ case x == 100:
+ x = -x
+ }
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRaceCaseFallthrough(t *testing.T) {
+ var x, y, z int
+ _ = y
+ ch := make(chan int, 2)
+ z = 1
+
+ go func() {
+ y = x
+ ch <- 1
+ }()
+ go func() {
+ switch {
+ case z == 1:
+ case z == 2:
+ x = 2
+ }
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceCaseFallthrough(t *testing.T) {
+ var x, y, z int
+ _ = y
+ ch := make(chan int, 2)
+ z = 1
+
+ go func() {
+ y = x
+ ch <- 1
+ }()
+ go func() {
+ switch {
+ case z == 1:
+ fallthrough
+ case z == 2:
+ x = 2
+ }
+ ch <- 1
+ }()
+
+ <-ch
+ <-ch
+}
+
+func TestRaceCaseIssue6418(t *testing.T) {
+ m := map[string]map[string]string{
+ "a": {
+ "b": "c",
+ },
+ }
+ ch := make(chan int)
+ go func() {
+ m["a"]["x"] = "y"
+ ch <- 1
+ }()
+ switch m["a"]["b"] {
+ }
+ <-ch
+}
+
+func TestRaceCaseType(t *testing.T) {
+ var x, y int
+ var i any = x
+ c := make(chan int, 1)
+ go func() {
+ switch i.(type) {
+ case nil:
+ case int:
+ }
+ c <- 1
+ }()
+ i = y
+ <-c
+}
+
+func TestRaceCaseTypeBody(t *testing.T) {
+ var x, y int
+ var i any = &x
+ c := make(chan int, 1)
+ go func() {
+ switch i := i.(type) {
+ case nil:
+ case *int:
+ *i = y
+ }
+ c <- 1
+ }()
+ x = y
+ <-c
+}
+
+func TestRaceCaseTypeIssue5890(t *testing.T) {
+ // spurious extra instrumentation of the initial interface
+ // value.
+ var x, y int
+ m := make(map[int]map[int]any)
+ m[0] = make(map[int]any)
+ c := make(chan int, 1)
+ go func() {
+ switch i := m[0][1].(type) {
+ case nil:
+ case *int:
+ *i = x
+ }
+ c <- 1
+ }()
+ m[0][1] = y
+ <-c
+}
+
+func TestNoRaceRange(t *testing.T) {
+ ch := make(chan int, 3)
+ a := [...]int{1, 2, 3}
+ for _, v := range a {
+ ch <- v
+ }
+ close(ch)
+}
+
+func TestNoRaceRangeIssue5446(t *testing.T) {
+ ch := make(chan int, 3)
+ a := []int{1, 2, 3}
+ b := []int{4}
+ // used to insert a spurious instrumentation of a[i]
+ // and crash.
+ i := 1
+ for i, a[i] = range b {
+ ch <- i
+ }
+ close(ch)
+}
+
+func TestRaceRange(t *testing.T) {
+ const N = 2
+ var a [N]int
+ var x, y int
+ _ = x + y
+ done := make(chan bool, N)
+ for i, v := range a {
+ go func(i int) {
+ // we don't want a write-vs-write race
+ // so there is no array b here
+ if i == 0 {
+ x = v
+ } else {
+ y = v
+ }
+ done <- true
+ }(i)
+ // Ensure the goroutine runs before we continue the loop.
+ runtime.Gosched()
+ }
+ for i := 0; i < N; i++ {
+ <-done
+ }
+}
+
+func TestRaceForInit(t *testing.T) {
+ c := make(chan int)
+ x := 0
+ go func() {
+ c <- x
+ }()
+ for x = 42; false; {
+ }
+ <-c
+}
+
+func TestNoRaceForInit(t *testing.T) {
+ done := make(chan bool)
+ c := make(chan bool)
+ x := 0
+ go func() {
+ for {
+ _, ok := <-c
+ if !ok {
+ done <- true
+ return
+ }
+ x++
+ }
+ }()
+ i := 0
+ for x = 42; i < 10; i++ {
+ c <- true
+ }
+ close(c)
+ <-done
+}
+
+func TestRaceForTest(t *testing.T) {
+ done := make(chan bool)
+ c := make(chan bool)
+ stop := false
+ go func() {
+ for {
+ _, ok := <-c
+ if !ok {
+ done <- true
+ return
+ }
+ stop = true
+ }
+ }()
+ for !stop {
+ c <- true
+ }
+ close(c)
+ <-done
+}
+
+func TestRaceForIncr(t *testing.T) {
+ done := make(chan bool)
+ c := make(chan bool)
+ x := 0
+ go func() {
+ for {
+ _, ok := <-c
+ if !ok {
+ done <- true
+ return
+ }
+ x++
+ }
+ }()
+ for i := 0; i < 10; x++ {
+ i++
+ c <- true
+ }
+ close(c)
+ <-done
+}
+
+func TestNoRaceForIncr(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ go func() {
+ x++
+ done <- true
+ }()
+ for i := 0; i < 0; x++ {
+ }
+ <-done
+}
+
+func TestRacePlus(t *testing.T) {
+ var x, y, z int
+ _ = y
+ ch := make(chan int, 2)
+
+ go func() {
+ y = x + z
+ ch <- 1
+ }()
+ go func() {
+ y = x + z + z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRacePlus2(t *testing.T) {
+ var x, y, z int
+ _ = y
+ ch := make(chan int, 2)
+
+ go func() {
+ x = 1
+ ch <- 1
+ }()
+ go func() {
+ y = +x + z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRacePlus(t *testing.T) {
+ var x, y, z, f int
+ _ = x + y + f
+ ch := make(chan int, 2)
+
+ go func() {
+ y = x + z
+ ch <- 1
+ }()
+ go func() {
+ f = z + x
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceComplement(t *testing.T) {
+ var x, y, z int
+ _ = x
+ ch := make(chan int, 2)
+
+ go func() {
+ x = ^y
+ ch <- 1
+ }()
+ go func() {
+ y = ^z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceDiv(t *testing.T) {
+ var x, y, z int
+ _ = x
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y / (z + 1)
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceDivConst(t *testing.T) {
+ var x, y, z uint32
+ _ = x
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y / 3 // involves only a HMUL node
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceMod(t *testing.T) {
+ var x, y, z int
+ _ = x
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y % (z + 1)
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceModConst(t *testing.T) {
+ var x, y, z int
+ _ = x
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y % 3
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceRotate(t *testing.T) {
+ var x, y, z uint32
+ _ = x
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y<<12 | y>>20
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+// May crash if the instrumentation is reckless.
+func TestNoRaceEnoughRegisters(t *testing.T) {
+ // from erf.go
+ const (
+ sa1 = 1
+ sa2 = 2
+ sa3 = 3
+ sa4 = 4
+ sa5 = 5
+ sa6 = 6
+ sa7 = 7
+ sa8 = 8
+ )
+ var s, S float64
+ s = 3.1415
+ S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8)))))))
+ s = S
+}
+
+// emptyFunc should not be inlined.
+func emptyFunc(x int) {
+ if false {
+ fmt.Println(x)
+ }
+}
+
+func TestRaceFuncArgument(t *testing.T) {
+ var x int
+ ch := make(chan bool, 1)
+ go func() {
+ emptyFunc(x)
+ ch <- true
+ }()
+ x = 1
+ <-ch
+}
+
+func TestRaceFuncArgument2(t *testing.T) {
+ var x int
+ ch := make(chan bool, 2)
+ go func() {
+ x = 42
+ ch <- true
+ }()
+ go func(y int) {
+ ch <- true
+ }(x)
+ <-ch
+ <-ch
+}
+
+func TestRaceSprint(t *testing.T) {
+ var x int
+ ch := make(chan bool, 1)
+ go func() {
+ fmt.Sprint(x)
+ ch <- true
+ }()
+ x = 1
+ <-ch
+}
+
+func TestRaceArrayCopy(t *testing.T) {
+ ch := make(chan bool, 1)
+ var a [5]int
+ go func() {
+ a[3] = 1
+ ch <- true
+ }()
+ a = [5]int{1, 2, 3, 4, 5}
+ <-ch
+}
+
+// Blows up a naive compiler.
+func TestRaceNestedArrayCopy(t *testing.T) {
+ ch := make(chan bool, 1)
+ type (
+ Point32 [2][2][2][2][2]Point
+ Point1024 [2][2][2][2][2]Point32
+ Point32k [2][2][2][2][2]Point1024
+ Point1M [2][2][2][2][2]Point32k
+ )
+ var a, b Point1M
+ go func() {
+ a[0][1][0][1][0][1][0][1][0][1][0][1][0][1][0][1][0][1][0][1].y = 1
+ ch <- true
+ }()
+ a = b
+ <-ch
+}
+
+func TestRaceStructRW(t *testing.T) {
+ p := Point{0, 0}
+ ch := make(chan bool, 1)
+ go func() {
+ p = Point{1, 1}
+ ch <- true
+ }()
+ q := p
+ <-ch
+ p = q
+}
+
+func TestRaceStructFieldRW1(t *testing.T) {
+ p := Point{0, 0}
+ ch := make(chan bool, 1)
+ go func() {
+ p.x = 1
+ ch <- true
+ }()
+ _ = p.x
+ <-ch
+}
+
+func TestNoRaceStructFieldRW1(t *testing.T) {
+ // Same struct, different variables, no
+ // pointers. The layout is known (at compile time?) ->
+ // no read on p
+ // writes on x and y
+ p := Point{0, 0}
+ ch := make(chan bool, 1)
+ go func() {
+ p.x = 1
+ ch <- true
+ }()
+ p.y = 1
+ <-ch
+ _ = p
+}
+
+func TestNoRaceStructFieldRW2(t *testing.T) {
+ // Same as NoRaceStructFieldRW1
+ // but p is a pointer, so there is a read on p
+ p := Point{0, 0}
+ ch := make(chan bool, 1)
+ go func() {
+ p.x = 1
+ ch <- true
+ }()
+ p.y = 1
+ <-ch
+ _ = p
+}
+
+func TestRaceStructFieldRW2(t *testing.T) {
+ p := &Point{0, 0}
+ ch := make(chan bool, 1)
+ go func() {
+ p.x = 1
+ ch <- true
+ }()
+ _ = p.x
+ <-ch
+}
+
+func TestRaceStructFieldRW3(t *testing.T) {
+ p := NamedPoint{name: "a", p: Point{0, 0}}
+ ch := make(chan bool, 1)
+ go func() {
+ p.p.x = 1
+ ch <- true
+ }()
+ _ = p.p.x
+ <-ch
+}
+
+func TestRaceEfaceWW(t *testing.T) {
+ var a, b any
+ ch := make(chan bool, 1)
+ go func() {
+ a = 1
+ ch <- true
+ }()
+ a = 2
+ <-ch
+ _, _ = a, b
+}
+
+func TestRaceIfaceWW(t *testing.T) {
+ var a, b Writer
+ ch := make(chan bool, 1)
+ go func() {
+ a = DummyWriter{1}
+ ch <- true
+ }()
+ a = DummyWriter{2}
+ <-ch
+ b = a
+ a = b
+}
+
+func TestRaceIfaceCmp(t *testing.T) {
+ var a, b Writer
+ a = DummyWriter{1}
+ ch := make(chan bool, 1)
+ go func() {
+ a = DummyWriter{1}
+ ch <- true
+ }()
+ _ = a == b
+ <-ch
+}
+
+func TestRaceIfaceCmpNil(t *testing.T) {
+ var a Writer
+ a = DummyWriter{1}
+ ch := make(chan bool, 1)
+ go func() {
+ a = DummyWriter{1}
+ ch <- true
+ }()
+ _ = a == nil
+ <-ch
+}
+
+func TestRaceEfaceConv(t *testing.T) {
+ c := make(chan bool)
+ v := 0
+ go func() {
+ go func(x any) {
+ }(v)
+ c <- true
+ }()
+ v = 42
+ <-c
+}
+
+type OsFile struct{}
+
+func (*OsFile) Read() {
+}
+
+type IoReader interface {
+ Read()
+}
+
+func TestRaceIfaceConv(t *testing.T) {
+ c := make(chan bool)
+ f := &OsFile{}
+ go func() {
+ go func(x IoReader) {
+ }(f)
+ c <- true
+ }()
+ f = &OsFile{}
+ <-c
+}
+
+func TestRaceError(t *testing.T) {
+ ch := make(chan bool, 1)
+ var err error
+ go func() {
+ err = nil
+ ch <- true
+ }()
+ _ = err
+ <-ch
+}
+
+func TestRaceIntptrRW(t *testing.T) {
+ var x, y int
+ var p *int = &x
+ ch := make(chan bool, 1)
+ go func() {
+ *p = 5
+ ch <- true
+ }()
+ y = *p
+ x = y
+ <-ch
+}
+
+func TestRaceStringRW(t *testing.T) {
+ ch := make(chan bool, 1)
+ s := ""
+ go func() {
+ s = "abacaba"
+ ch <- true
+ }()
+ _ = s
+ <-ch
+}
+
+func TestRaceStringPtrRW(t *testing.T) {
+ ch := make(chan bool, 1)
+ var x string
+ p := &x
+ go func() {
+ *p = "a"
+ ch <- true
+ }()
+ _ = *p
+ <-ch
+}
+
+func TestRaceFloat64WW(t *testing.T) {
+ var x, y float64
+ ch := make(chan bool, 1)
+ go func() {
+ x = 1.0
+ ch <- true
+ }()
+ x = 2.0
+ <-ch
+
+ y = x
+ x = y
+}
+
+func TestRaceComplex128WW(t *testing.T) {
+ var x, y complex128
+ ch := make(chan bool, 1)
+ go func() {
+ x = 2 + 2i
+ ch <- true
+ }()
+ x = 4 + 4i
+ <-ch
+
+ y = x
+ x = y
+}
+
+func TestRaceUnsafePtrRW(t *testing.T) {
+ var x, y, z int
+ x, y, z = 1, 2, 3
+ var p unsafe.Pointer = unsafe.Pointer(&x)
+ ch := make(chan bool, 1)
+ go func() {
+ p = (unsafe.Pointer)(&z)
+ ch <- true
+ }()
+ y = *(*int)(p)
+ x = y
+ <-ch
+}
+
+func TestRaceFuncVariableRW(t *testing.T) {
+ var f func(x int) int
+ f = func(x int) int {
+ return x * x
+ }
+ ch := make(chan bool, 1)
+ go func() {
+ f = func(x int) int {
+ return x
+ }
+ ch <- true
+ }()
+ y := f(1)
+ <-ch
+ x := y
+ y = x
+}
+
+func TestRaceFuncVariableWW(t *testing.T) {
+ var f func(x int) int
+ _ = f
+ ch := make(chan bool, 1)
+ go func() {
+ f = func(x int) int {
+ return x
+ }
+ ch <- true
+ }()
+ f = func(x int) int {
+ return x * x
+ }
+ <-ch
+}
+
+// This one should not belong to mop_test
+func TestRacePanic(t *testing.T) {
+ var x int
+ _ = x
+ var zero int = 0
+ ch := make(chan bool, 2)
+ go func() {
+ defer func() {
+ err := recover()
+ if err == nil {
+ panic("should be panicking")
+ }
+ x = 1
+ ch <- true
+ }()
+ var y int = 1 / zero
+ zero = y
+ }()
+ go func() {
+ defer func() {
+ err := recover()
+ if err == nil {
+ panic("should be panicking")
+ }
+ x = 2
+ ch <- true
+ }()
+ var y int = 1 / zero
+ zero = y
+ }()
+
+ <-ch
+ <-ch
+ if zero != 0 {
+ panic("zero has changed")
+ }
+}
+
+func TestNoRaceBlank(t *testing.T) {
+ var a [5]int
+ ch := make(chan bool, 1)
+ go func() {
+ _, _ = a[0], a[1]
+ ch <- true
+ }()
+ _, _ = a[2], a[3]
+ <-ch
+ a[1] = a[0]
+}
+
+func TestRaceAppendRW(t *testing.T) {
+ a := make([]int, 10)
+ ch := make(chan bool)
+ go func() {
+ _ = append(a, 1)
+ ch <- true
+ }()
+ a[0] = 1
+ <-ch
+}
+
+func TestRaceAppendLenRW(t *testing.T) {
+ a := make([]int, 0)
+ ch := make(chan bool)
+ go func() {
+ a = append(a, 1)
+ ch <- true
+ }()
+ _ = len(a)
+ <-ch
+}
+
+func TestRaceAppendCapRW(t *testing.T) {
+ a := make([]int, 0)
+ ch := make(chan string)
+ go func() {
+ a = append(a, 1)
+ ch <- ""
+ }()
+ _ = cap(a)
+ <-ch
+}
+
+func TestNoRaceFuncArgsRW(t *testing.T) {
+ ch := make(chan byte, 1)
+ var x byte
+ go func(y byte) {
+ _ = y
+ ch <- 0
+ }(x)
+ x = 1
+ <-ch
+}
+
+func TestRaceFuncArgsRW(t *testing.T) {
+ ch := make(chan byte, 1)
+ var x byte
+ go func(y *byte) {
+ _ = *y
+ ch <- 0
+ }(&x)
+ x = 1
+ <-ch
+}
+
+// from the mailing list, slightly modified
+// unprotected concurrent access to seen[]
+func TestRaceCrawl(t *testing.T) {
+ url := "dummyurl"
+ depth := 3
+ seen := make(map[string]bool)
+ ch := make(chan int, 100)
+ var wg sync.WaitGroup
+ var crawl func(string, int)
+ crawl = func(u string, d int) {
+ nurl := 0
+ defer func() {
+ ch <- nurl
+ }()
+ seen[u] = true
+ if d <= 0 {
+ wg.Done()
+ return
+ }
+ urls := [...]string{"a", "b", "c"}
+ for _, uu := range urls {
+ if _, ok := seen[uu]; !ok {
+ wg.Add(1)
+ go crawl(uu, d-1)
+ nurl++
+ }
+ }
+ wg.Done()
+ }
+ wg.Add(1)
+ go crawl(url, depth)
+ wg.Wait()
+}
+
+func TestRaceIndirection(t *testing.T) {
+ ch := make(chan struct{}, 1)
+ var y int
+ var x *int = &y
+ go func() {
+ *x = 1
+ ch <- struct{}{}
+ }()
+ *x = 2
+ <-ch
+ _ = *x
+}
+
+func TestRaceRune(t *testing.T) {
+ c := make(chan bool)
+ var x rune
+ go func() {
+ x = 1
+ c <- true
+ }()
+ _ = x
+ <-c
+}
+
+func TestRaceEmptyInterface1(t *testing.T) {
+ c := make(chan bool)
+ var x any
+ go func() {
+ x = nil
+ c <- true
+ }()
+ _ = x
+ <-c
+}
+
+func TestRaceEmptyInterface2(t *testing.T) {
+ c := make(chan bool)
+ var x any
+ go func() {
+ x = &Point{}
+ c <- true
+ }()
+ _ = x
+ <-c
+}
+
+func TestRaceTLS(t *testing.T) {
+ comm := make(chan *int)
+ done := make(chan bool, 2)
+ go func() {
+ var x int
+ comm <- &x
+ x = 1
+ x = *(<-comm)
+ done <- true
+ }()
+ go func() {
+ p := <-comm
+ *p = 2
+ comm <- p
+ done <- true
+ }()
+ <-done
+ <-done
+}
+
+func TestNoRaceHeapReallocation(t *testing.T) {
+ // It is possible that a future implementation
+ // of memory allocation will ruin this test.
+ // Increasing n might help in this case, so
+ // this test is a bit more generic than most of the
+ // others.
+ const n = 2
+ done := make(chan bool, n)
+ empty := func(p *int) {}
+ for i := 0; i < n; i++ {
+ ms := i
+ go func() {
+ <-time.After(time.Duration(ms) * time.Millisecond)
+ runtime.GC()
+ var x int
+ empty(&x) // x goes to the heap
+ done <- true
+ }()
+ }
+ for i := 0; i < n; i++ {
+ <-done
+ }
+}
+
+func TestRaceAnd(t *testing.T) {
+ c := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ x = 1
+ c <- true
+ }()
+ if x == 1 && y == 1 {
+ }
+ <-c
+}
+
+func TestRaceAnd2(t *testing.T) {
+ c := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ x = 1
+ c <- true
+ }()
+ if y == 0 && x == 1 {
+ }
+ <-c
+}
+
+func TestNoRaceAnd(t *testing.T) {
+ c := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ x = 1
+ c <- true
+ }()
+ if y == 1 && x == 1 {
+ }
+ <-c
+}
+
+func TestRaceOr(t *testing.T) {
+ c := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ x = 1
+ c <- true
+ }()
+ if x == 1 || y == 1 {
+ }
+ <-c
+}
+
+func TestRaceOr2(t *testing.T) {
+ c := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ x = 1
+ c <- true
+ }()
+ if y == 1 || x == 1 {
+ }
+ <-c
+}
+
+func TestNoRaceOr(t *testing.T) {
+ c := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ x = 1
+ c <- true
+ }()
+ if y == 0 || x == 1 {
+ }
+ <-c
+}
+
+func TestNoRaceShortCalc(t *testing.T) {
+ c := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ y = 1
+ c <- true
+ }()
+ if x == 0 || y == 0 {
+ }
+ <-c
+}
+
+func TestNoRaceShortCalc2(t *testing.T) {
+ c := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ y = 1
+ c <- true
+ }()
+ if x == 1 && y == 0 {
+ }
+ <-c
+}
+
+func TestRaceFuncItself(t *testing.T) {
+ c := make(chan bool)
+ f := func() {}
+ go func() {
+ f()
+ c <- true
+ }()
+ f = func() {}
+ <-c
+}
+
+func TestNoRaceFuncUnlock(t *testing.T) {
+ ch := make(chan bool, 1)
+ var mu sync.Mutex
+ x := 0
+ _ = x
+ go func() {
+ mu.Lock()
+ x = 42
+ mu.Unlock()
+ ch <- true
+ }()
+ x = func(mu *sync.Mutex) int {
+ mu.Lock()
+ return 43
+ }(&mu)
+ mu.Unlock()
+ <-ch
+}
+
+func TestRaceStructInit(t *testing.T) {
+ type X struct {
+ x, y int
+ }
+ c := make(chan bool, 1)
+ y := 0
+ go func() {
+ y = 42
+ c <- true
+ }()
+ x := X{x: y}
+ _ = x
+ <-c
+}
+
+func TestRaceArrayInit(t *testing.T) {
+ c := make(chan bool, 1)
+ y := 0
+ go func() {
+ y = 42
+ c <- true
+ }()
+ x := []int{0, y, 42}
+ _ = x
+ <-c
+}
+
+func TestRaceMapInit(t *testing.T) {
+ c := make(chan bool, 1)
+ y := 0
+ go func() {
+ y = 42
+ c <- true
+ }()
+ x := map[int]int{0: 42, y: 42}
+ _ = x
+ <-c
+}
+
+func TestRaceMapInit2(t *testing.T) {
+ c := make(chan bool, 1)
+ y := 0
+ go func() {
+ y = 42
+ c <- true
+ }()
+ x := map[int]int{0: 42, 42: y}
+ _ = x
+ <-c
+}
+
+type Inter interface {
+ Foo(x int)
+}
+type InterImpl struct {
+ x, y int
+}
+
+//go:noinline
+func (p InterImpl) Foo(x int) {
+}
+
+type InterImpl2 InterImpl
+
+func (p *InterImpl2) Foo(x int) {
+ if p == nil {
+ InterImpl{}.Foo(x)
+ }
+ InterImpl(*p).Foo(x)
+}
+
+func TestRaceInterCall(t *testing.T) {
+ c := make(chan bool, 1)
+ p := InterImpl{}
+ var x Inter = p
+ go func() {
+ p2 := InterImpl{}
+ x = p2
+ c <- true
+ }()
+ x.Foo(0)
+ <-c
+}
+
+func TestRaceInterCall2(t *testing.T) {
+ c := make(chan bool, 1)
+ p := InterImpl{}
+ var x Inter = p
+ z := 0
+ go func() {
+ z = 42
+ c <- true
+ }()
+ x.Foo(z)
+ <-c
+}
+
+func TestRaceFuncCall(t *testing.T) {
+ c := make(chan bool, 1)
+ f := func(x, y int) {}
+ x, y := 0, 0
+ go func() {
+ y = 42
+ c <- true
+ }()
+ f(x, y)
+ <-c
+}
+
+func TestRaceMethodCall(t *testing.T) {
+ c := make(chan bool, 1)
+ i := InterImpl{}
+ x := 0
+ go func() {
+ x = 42
+ c <- true
+ }()
+ i.Foo(x)
+ <-c
+}
+
+func TestRaceMethodCall2(t *testing.T) {
+ c := make(chan bool, 1)
+ i := &InterImpl{}
+ go func() {
+ i = &InterImpl{}
+ c <- true
+ }()
+ i.Foo(0)
+ <-c
+}
+
+// Method value with concrete value receiver.
+func TestRaceMethodValue(t *testing.T) {
+ c := make(chan bool, 1)
+ i := InterImpl{}
+ go func() {
+ i = InterImpl{}
+ c <- true
+ }()
+ _ = i.Foo
+ <-c
+}
+
+// Method value with interface receiver.
+func TestRaceMethodValue2(t *testing.T) {
+ c := make(chan bool, 1)
+ var i Inter = InterImpl{}
+ go func() {
+ i = InterImpl{}
+ c <- true
+ }()
+ _ = i.Foo
+ <-c
+}
+
+// Method value with implicit dereference.
+func TestRaceMethodValue3(t *testing.T) {
+ c := make(chan bool, 1)
+ i := &InterImpl{}
+ go func() {
+ *i = InterImpl{}
+ c <- true
+ }()
+ _ = i.Foo // dereferences i.
+ <-c
+}
+
+// Method value implicitly taking receiver address.
+func TestNoRaceMethodValue(t *testing.T) {
+ c := make(chan bool, 1)
+ i := InterImpl2{}
+ go func() {
+ i = InterImpl2{}
+ c <- true
+ }()
+ _ = i.Foo // takes the address of i only.
+ <-c
+}
+
+func TestRacePanicArg(t *testing.T) {
+ c := make(chan bool, 1)
+ err := errors.New("err")
+ go func() {
+ err = errors.New("err2")
+ c <- true
+ }()
+ defer func() {
+ recover()
+ <-c
+ }()
+ panic(err)
+}
+
+func TestRaceDeferArg(t *testing.T) {
+ c := make(chan bool, 1)
+ x := 0
+ go func() {
+ x = 42
+ c <- true
+ }()
+ func() {
+ defer func(x int) {
+ }(x)
+ }()
+ <-c
+}
+
+type DeferT int
+
+func (d DeferT) Foo() {
+}
+
+func TestRaceDeferArg2(t *testing.T) {
+ c := make(chan bool, 1)
+ var x DeferT
+ go func() {
+ var y DeferT
+ x = y
+ c <- true
+ }()
+ func() {
+ defer x.Foo()
+ }()
+ <-c
+}
+
+func TestNoRaceAddrExpr(t *testing.T) {
+ c := make(chan bool, 1)
+ x := 0
+ go func() {
+ x = 42
+ c <- true
+ }()
+ _ = &x
+ <-c
+}
+
+type AddrT struct {
+ _ [256]byte
+ x int
+}
+
+type AddrT2 struct {
+ _ [512]byte
+ p *AddrT
+}
+
+func TestRaceAddrExpr(t *testing.T) {
+ c := make(chan bool, 1)
+ a := AddrT2{p: &AddrT{x: 42}}
+ go func() {
+ a.p = &AddrT{x: 43}
+ c <- true
+ }()
+ _ = &a.p.x
+ <-c
+}
+
+func TestRaceTypeAssert(t *testing.T) {
+ c := make(chan bool, 1)
+ x := 0
+ var i any = x
+ go func() {
+ y := 0
+ i = y
+ c <- true
+ }()
+ _ = i.(int)
+ <-c
+}
+
+func TestRaceBlockAs(t *testing.T) {
+ c := make(chan bool, 1)
+ var x, y int
+ go func() {
+ x = 42
+ c <- true
+ }()
+ x, y = y, x
+ <-c
+}
+
+func TestRaceBlockCall1(t *testing.T) {
+ done := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ f := func() (int, int) {
+ return 42, 43
+ }
+ x, y = f()
+ done <- true
+ }()
+ _ = x
+ <-done
+ if x != 42 || y != 43 {
+ panic("corrupted data")
+ }
+}
+func TestRaceBlockCall2(t *testing.T) {
+ done := make(chan bool)
+ x, y := 0, 0
+ go func() {
+ f := func() (int, int) {
+ return 42, 43
+ }
+ x, y = f()
+ done <- true
+ }()
+ _ = y
+ <-done
+ if x != 42 || y != 43 {
+ panic("corrupted data")
+ }
+}
+func TestRaceBlockCall3(t *testing.T) {
+ done := make(chan bool)
+ var x *int
+ y := 0
+ go func() {
+ f := func() (*int, int) {
+ i := 42
+ return &i, 43
+ }
+ x, y = f()
+ done <- true
+ }()
+ _ = x
+ <-done
+ if *x != 42 || y != 43 {
+ panic("corrupted data")
+ }
+}
+func TestRaceBlockCall4(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ var y *int
+ go func() {
+ f := func() (int, *int) {
+ i := 43
+ return 42, &i
+ }
+ x, y = f()
+ done <- true
+ }()
+ _ = y
+ <-done
+ if x != 42 || *y != 43 {
+ panic("corrupted data")
+ }
+}
+func TestRaceBlockCall5(t *testing.T) {
+ done := make(chan bool)
+ var x *int
+ y := 0
+ go func() {
+ f := func() (*int, int) {
+ i := 42
+ return &i, 43
+ }
+ x, y = f()
+ done <- true
+ }()
+ _ = y
+ <-done
+ if *x != 42 || y != 43 {
+ panic("corrupted data")
+ }
+}
+func TestRaceBlockCall6(t *testing.T) {
+ done := make(chan bool)
+ x := 0
+ var y *int
+ go func() {
+ f := func() (int, *int) {
+ i := 43
+ return 42, &i
+ }
+ x, y = f()
+ done <- true
+ }()
+ _ = x
+ <-done
+ if x != 42 || *y != 43 {
+ panic("corrupted data")
+ }
+}
+func TestRaceSliceSlice(t *testing.T) {
+ c := make(chan bool, 1)
+ x := make([]int, 10)
+ go func() {
+ x = make([]int, 20)
+ c <- true
+ }()
+ _ = x[2:3]
+ <-c
+}
+
+func TestRaceSliceSlice2(t *testing.T) {
+ c := make(chan bool, 1)
+ x := make([]int, 10)
+ i := 2
+ go func() {
+ i = 3
+ c <- true
+ }()
+ _ = x[i:4]
+ <-c
+}
+
+func TestRaceSliceString(t *testing.T) {
+ c := make(chan bool, 1)
+ x := "hello"
+ go func() {
+ x = "world"
+ c <- true
+ }()
+ _ = x[2:3]
+ <-c
+}
+
+func TestRaceSliceStruct(t *testing.T) {
+ type X struct {
+ x, y int
+ }
+ c := make(chan bool, 1)
+ x := make([]X, 10)
+ go func() {
+ y := make([]X, 10)
+ copy(y, x)
+ c <- true
+ }()
+ x[1].y = 42
+ <-c
+}
+
+func TestRaceAppendSliceStruct(t *testing.T) {
+ type X struct {
+ x, y int
+ }
+ c := make(chan bool, 1)
+ x := make([]X, 10)
+ go func() {
+ y := make([]X, 0, 10)
+ y = append(y, x...)
+ c <- true
+ }()
+ x[1].y = 42
+ <-c
+}
+
+func TestRaceStructInd(t *testing.T) {
+ c := make(chan bool, 1)
+ type Item struct {
+ x, y int
+ }
+ i := Item{}
+ go func(p *Item) {
+ *p = Item{}
+ c <- true
+ }(&i)
+ i.y = 42
+ <-c
+}
+
+func TestRaceAsFunc1(t *testing.T) {
+ var s []byte
+ c := make(chan bool, 1)
+ go func() {
+ var err error
+ s, err = func() ([]byte, error) {
+ t := []byte("hello world")
+ return t, nil
+ }()
+ c <- true
+ _ = err
+ }()
+ _ = string(s)
+ <-c
+}
+
+func TestRaceAsFunc2(t *testing.T) {
+ c := make(chan bool, 1)
+ x := 0
+ go func() {
+ func(x int) {
+ }(x)
+ c <- true
+ }()
+ x = 42
+ <-c
+}
+
+func TestRaceAsFunc3(t *testing.T) {
+ c := make(chan bool, 1)
+ var mu sync.Mutex
+ x := 0
+ go func() {
+ func(x int) {
+ mu.Lock()
+ }(x) // Read of x must be outside of the mutex.
+ mu.Unlock()
+ c <- true
+ }()
+ mu.Lock()
+ x = 42
+ mu.Unlock()
+ <-c
+}
+
+func TestNoRaceAsFunc4(t *testing.T) {
+ c := make(chan bool, 1)
+ var mu sync.Mutex
+ x := 0
+ _ = x
+ go func() {
+ x = func() int { // Write of x must be under the mutex.
+ mu.Lock()
+ return 42
+ }()
+ mu.Unlock()
+ c <- true
+ }()
+ mu.Lock()
+ x = 42
+ mu.Unlock()
+ <-c
+}
+
+func TestRaceHeapParam(t *testing.T) {
+ done := make(chan bool)
+ x := func() (x int) {
+ go func() {
+ x = 42
+ done <- true
+ }()
+ return
+ }()
+ _ = x
+ <-done
+}
+
+func TestNoRaceEmptyStruct(t *testing.T) {
+ type Empty struct{}
+ type X struct {
+ y int64
+ Empty
+ }
+ type Y struct {
+ x X
+ y int64
+ }
+ c := make(chan X)
+ var y Y
+ go func() {
+ x := y.x
+ c <- x
+ }()
+ y.y = 42
+ <-c
+}
+
+func TestRaceNestedStruct(t *testing.T) {
+ type X struct {
+ x, y int
+ }
+ type Y struct {
+ x X
+ }
+ c := make(chan Y)
+ var y Y
+ go func() {
+ c <- y
+ }()
+ y.x.y = 42
+ <-c
+}
+
+func TestRaceIssue5567(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ in := make(chan []byte)
+ res := make(chan error)
+ go func() {
+ var err error
+ defer func() {
+ close(in)
+ res <- err
+ }()
+ path := "mop_test.go"
+ f, err := os.Open(path)
+ if err != nil {
+ return
+ }
+ defer f.Close()
+ var n, total int
+ b := make([]byte, 17) // the race is on b buffer
+ for err == nil {
+ n, err = f.Read(b)
+ total += n
+ if n > 0 {
+ in <- b[:n]
+ }
+ }
+ if err == io.EOF {
+ err = nil
+ }
+ }()
+ h := sha1.New()
+ for b := range in {
+ h.Write(b)
+ }
+ _ = h.Sum(nil)
+ err := <-res
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestRaceIssue5654(t *testing.T) {
+ text := `Friends, Romans, countrymen, lend me your ears;
+I come to bury Caesar, not to praise him.
+The evil that men do lives after them;
+The good is oft interred with their bones;
+So let it be with Caesar. The noble Brutus
+Hath told you Caesar was ambitious:
+If it were so, it was a grievous fault,
+And grievously hath Caesar answer'd it.
+Here, under leave of Brutus and the rest -
+For Brutus is an honourable man;
+So are they all, all honourable men -
+Come I to speak in Caesar's funeral.
+He was my friend, faithful and just to me:
+But Brutus says he was ambitious;
+And Brutus is an honourable man.`
+
+ data := bytes.NewBufferString(text)
+ in := make(chan []byte)
+
+ go func() {
+ buf := make([]byte, 16)
+ var n int
+ var err error
+ for ; err == nil; n, err = data.Read(buf) {
+ in <- buf[:n]
+ }
+ close(in)
+ }()
+ res := ""
+ for s := range in {
+ res += string(s)
+ }
+ _ = res
+}
+
+type Base int
+
+func (b *Base) Foo() int {
+ return 42
+}
+
+func (b Base) Bar() int {
+ return int(b)
+}
+
+func TestNoRaceMethodThunk(t *testing.T) {
+ type Derived struct {
+ pad int
+ Base
+ }
+ var d Derived
+ done := make(chan bool)
+ go func() {
+ _ = d.Foo()
+ done <- true
+ }()
+ d = Derived{}
+ <-done
+}
+
+func TestRaceMethodThunk(t *testing.T) {
+ type Derived struct {
+ pad int
+ *Base
+ }
+ var d Derived
+ done := make(chan bool)
+ go func() {
+ _ = d.Foo()
+ done <- true
+ }()
+ d = Derived{}
+ <-done
+}
+
+func TestRaceMethodThunk2(t *testing.T) {
+ type Derived struct {
+ pad int
+ Base
+ }
+ var d Derived
+ done := make(chan bool)
+ go func() {
+ _ = d.Bar()
+ done <- true
+ }()
+ d = Derived{}
+ <-done
+}
+
+func TestRaceMethodThunk3(t *testing.T) {
+ type Derived struct {
+ pad int
+ *Base
+ }
+ var d Derived
+ d.Base = new(Base)
+ done := make(chan bool)
+ go func() {
+ _ = d.Bar()
+ done <- true
+ }()
+ d.Base = new(Base)
+ <-done
+}
+
+func TestRaceMethodThunk4(t *testing.T) {
+ type Derived struct {
+ pad int
+ *Base
+ }
+ var d Derived
+ d.Base = new(Base)
+ done := make(chan bool)
+ go func() {
+ _ = d.Bar()
+ done <- true
+ }()
+ *(*int)(d.Base) = 42
+ <-done
+}
+
+func TestNoRaceTinyAlloc(t *testing.T) {
+ const P = 4
+ const N = 1e6
+ var tinySink *byte
+ _ = tinySink
+ done := make(chan bool)
+ for p := 0; p < P; p++ {
+ go func() {
+ for i := 0; i < N; i++ {
+ var b byte
+ if b != 0 {
+ tinySink = &b // make it heap allocated
+ }
+ b = 42
+ }
+ done <- true
+ }()
+ }
+ for p := 0; p < P; p++ {
+ <-done
+ }
+}
diff --git a/src/runtime/race/testdata/mutex_test.go b/src/runtime/race/testdata/mutex_test.go
new file mode 100644
index 0000000..9dbed9a
--- /dev/null
+++ b/src/runtime/race/testdata/mutex_test.go
@@ -0,0 +1,150 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestNoRaceMutex(t *testing.T) {
+ var mu sync.Mutex
+ var x int16 = 0
+ _ = x
+ ch := make(chan bool, 2)
+ go func() {
+ mu.Lock()
+ defer mu.Unlock()
+ x = 1
+ ch <- true
+ }()
+ go func() {
+ mu.Lock()
+ x = 2
+ mu.Unlock()
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceMutex(t *testing.T) {
+ var mu sync.Mutex
+ var x int16 = 0
+ _ = x
+ ch := make(chan bool, 2)
+ go func() {
+ x = 1
+ mu.Lock()
+ defer mu.Unlock()
+ ch <- true
+ }()
+ go func() {
+ x = 2
+ mu.Lock()
+ mu.Unlock()
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceMutex2(t *testing.T) {
+ var mu1 sync.Mutex
+ var mu2 sync.Mutex
+ var x int8 = 0
+ _ = x
+ ch := make(chan bool, 2)
+ go func() {
+ mu1.Lock()
+ defer mu1.Unlock()
+ x = 1
+ ch <- true
+ }()
+ go func() {
+ mu2.Lock()
+ x = 2
+ mu2.Unlock()
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRaceMutexPureHappensBefore(t *testing.T) {
+ var mu sync.Mutex
+ var x int16 = 0
+ _ = x
+ written := false
+ ch := make(chan bool, 2)
+ go func() {
+ x = 1
+ mu.Lock()
+ written = true
+ mu.Unlock()
+ ch <- true
+ }()
+ go func() {
+ time.Sleep(100 * time.Microsecond)
+ mu.Lock()
+ for !written {
+ mu.Unlock()
+ time.Sleep(100 * time.Microsecond)
+ mu.Lock()
+ }
+ mu.Unlock()
+ x = 1
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRaceMutexSemaphore(t *testing.T) {
+ var mu sync.Mutex
+ ch := make(chan bool, 2)
+ x := 0
+ _ = x
+ mu.Lock()
+ go func() {
+ x = 1
+ mu.Unlock()
+ ch <- true
+ }()
+ go func() {
+ mu.Lock()
+ x = 2
+ mu.Unlock()
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+// from doc/go_mem.html
+func TestNoRaceMutexExampleFromHtml(t *testing.T) {
+ var l sync.Mutex
+ a := ""
+
+ l.Lock()
+ go func() {
+ a = "hello, world"
+ l.Unlock()
+ }()
+ l.Lock()
+ _ = a
+}
+
+func TestRaceMutexOverwrite(t *testing.T) {
+ c := make(chan bool, 1)
+ var mu sync.Mutex
+ go func() {
+ mu = sync.Mutex{}
+ c <- true
+ }()
+ mu.Lock()
+ <-c
+}
diff --git a/src/runtime/race/testdata/pool_test.go b/src/runtime/race/testdata/pool_test.go
new file mode 100644
index 0000000..a96913e
--- /dev/null
+++ b/src/runtime/race/testdata/pool_test.go
@@ -0,0 +1,47 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestRacePool(t *testing.T) {
+ // Pool randomly drops the argument on the floor during Put.
+ // Repeat so that at least one iteration gets reuse.
+ for i := 0; i < 10; i++ {
+ c := make(chan int)
+ p := &sync.Pool{New: func() any { return make([]byte, 10) }}
+ x := p.Get().([]byte)
+ x[0] = 1
+ p.Put(x)
+ go func() {
+ y := p.Get().([]byte)
+ y[0] = 2
+ c <- 1
+ }()
+ x[0] = 3
+ <-c
+ }
+}
+
+func TestNoRacePool(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ p := &sync.Pool{New: func() any { return make([]byte, 10) }}
+ x := p.Get().([]byte)
+ x[0] = 1
+ p.Put(x)
+ go func() {
+ y := p.Get().([]byte)
+ y[0] = 2
+ p.Put(y)
+ }()
+ time.Sleep(100 * time.Millisecond)
+ x = p.Get().([]byte)
+ x[0] = 3
+ }
+}
diff --git a/src/runtime/race/testdata/reflect_test.go b/src/runtime/race/testdata/reflect_test.go
new file mode 100644
index 0000000..b567400
--- /dev/null
+++ b/src/runtime/race/testdata/reflect_test.go
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestRaceReflectRW(t *testing.T) {
+ ch := make(chan bool, 1)
+ i := 0
+ v := reflect.ValueOf(&i)
+ go func() {
+ v.Elem().Set(reflect.ValueOf(1))
+ ch <- true
+ }()
+ _ = v.Elem().Int()
+ <-ch
+}
+
+func TestRaceReflectWW(t *testing.T) {
+ ch := make(chan bool, 1)
+ i := 0
+ v := reflect.ValueOf(&i)
+ go func() {
+ v.Elem().Set(reflect.ValueOf(1))
+ ch <- true
+ }()
+ v.Elem().Set(reflect.ValueOf(2))
+ <-ch
+}
+
+func TestRaceReflectCopyWW(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]byte, 2)
+ v := reflect.ValueOf(a)
+ go func() {
+ reflect.Copy(v, v)
+ ch <- true
+ }()
+ reflect.Copy(v, v)
+ <-ch
+}
diff --git a/src/runtime/race/testdata/regression_test.go b/src/runtime/race/testdata/regression_test.go
new file mode 100644
index 0000000..6a7802f
--- /dev/null
+++ b/src/runtime/race/testdata/regression_test.go
@@ -0,0 +1,189 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code patterns that caused problems in the past.
+
+package race_test
+
+import (
+ "testing"
+)
+
+type LogImpl struct {
+ x int
+}
+
+func NewLog() (l LogImpl) {
+ c := make(chan bool)
+ go func() {
+ _ = l
+ c <- true
+ }()
+ l = LogImpl{}
+ <-c
+ return
+}
+
+var _ LogImpl = NewLog()
+
+func MakeMap() map[int]int {
+ return make(map[int]int)
+}
+
+func InstrumentMapLen() {
+ _ = len(MakeMap())
+}
+
+func InstrumentMapLen2() {
+ m := make(map[int]map[int]int)
+ _ = len(m[0])
+}
+
+func InstrumentMapLen3() {
+ m := make(map[int]*map[int]int)
+ _ = len(*m[0])
+}
+
+func TestRaceUnaddressableMapLen(t *testing.T) {
+ m := make(map[int]map[int]int)
+ ch := make(chan int, 1)
+ m[0] = make(map[int]int)
+ go func() {
+ _ = len(m[0])
+ ch <- 0
+ }()
+ m[0][0] = 1
+ <-ch
+}
+
+type Rect struct {
+ x, y int
+}
+
+type Image struct {
+ min, max Rect
+}
+
+//go:noinline
+func NewImage() Image {
+ return Image{}
+}
+
+func AddrOfTemp() {
+ _ = NewImage().min
+}
+
+type TypeID int
+
+func (t *TypeID) encodeType(x int) (tt TypeID, err error) {
+ switch x {
+ case 0:
+ return t.encodeType(x * x)
+ }
+ return 0, nil
+}
+
+type stack []int
+
+func (s *stack) push(x int) {
+ *s = append(*s, x)
+}
+
+func (s *stack) pop() int {
+ i := len(*s)
+ n := (*s)[i-1]
+ *s = (*s)[:i-1]
+ return n
+}
+
+func TestNoRaceStackPushPop(t *testing.T) {
+ var s stack
+ go func(s *stack) {}(&s)
+ s.push(1)
+ x := s.pop()
+ _ = x
+}
+
+type RpcChan struct {
+ c chan bool
+}
+
+var makeChanCalls int
+
+//go:noinline
+func makeChan() *RpcChan {
+ makeChanCalls++
+ c := &RpcChan{make(chan bool, 1)}
+ c.c <- true
+ return c
+}
+
+func call() bool {
+ x := <-makeChan().c
+ return x
+}
+
+func TestNoRaceRpcChan(t *testing.T) {
+ makeChanCalls = 0
+ _ = call()
+ if makeChanCalls != 1 {
+ t.Fatalf("makeChanCalls %d, expected 1\n", makeChanCalls)
+ }
+}
+
+func divInSlice() {
+ v := make([]int64, 10)
+ i := 1
+ _ = v[(i*4)/3]
+}
+
+func TestNoRaceReturn(t *testing.T) {
+ c := make(chan int)
+ noRaceReturn(c)
+ <-c
+}
+
+// Return used to do an implicit a = a, causing a read/write race
+// with the goroutine. Compiler has an optimization to avoid that now.
+// See issue 4014.
+func noRaceReturn(c chan int) (a, b int) {
+ a = 42
+ go func() {
+ _ = a
+ c <- 1
+ }()
+ return a, 10
+}
+
+func issue5431() {
+ var p **inltype
+ if inlinetest(p).x && inlinetest(p).y {
+ } else if inlinetest(p).x || inlinetest(p).y {
+ }
+}
+
+type inltype struct {
+ x, y bool
+}
+
+func inlinetest(p **inltype) *inltype {
+ return *p
+}
+
+type iface interface {
+ Foo() *struct{ b bool }
+}
+
+type Int int
+
+func (i Int) Foo() *struct{ b bool } {
+ return &struct{ b bool }{false}
+}
+
+func TestNoRaceForInfiniteLoop(t *testing.T) {
+ var x Int
+ // interface conversion causes nodes to be put on init list
+ for iface(x).Foo().b {
+ }
+}
diff --git a/src/runtime/race/testdata/rwmutex_test.go b/src/runtime/race/testdata/rwmutex_test.go
new file mode 100644
index 0000000..39219e5
--- /dev/null
+++ b/src/runtime/race/testdata/rwmutex_test.go
@@ -0,0 +1,154 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestRaceMutexRWMutex(t *testing.T) {
+ var mu1 sync.Mutex
+ var mu2 sync.RWMutex
+ var x int16 = 0
+ _ = x
+ ch := make(chan bool, 2)
+ go func() {
+ mu1.Lock()
+ defer mu1.Unlock()
+ x = 1
+ ch <- true
+ }()
+ go func() {
+ mu2.Lock()
+ x = 2
+ mu2.Unlock()
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestNoRaceRWMutex(t *testing.T) {
+ var mu sync.RWMutex
+ var x, y int64 = 0, 1
+ _ = y
+ ch := make(chan bool, 2)
+ go func() {
+ mu.Lock()
+ defer mu.Unlock()
+ x = 2
+ ch <- true
+ }()
+ go func() {
+ mu.RLock()
+ y = x
+ mu.RUnlock()
+ ch <- true
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceRWMutexMultipleReaders(t *testing.T) {
+ var mu sync.RWMutex
+ var x, y int64 = 0, 1
+ ch := make(chan bool, 4)
+ go func() {
+ mu.Lock()
+ defer mu.Unlock()
+ x = 2
+ ch <- true
+ }()
+ // Use three readers so that no matter what order they're
+ // scheduled in, two will be on the same side of the write
+ // lock above.
+ go func() {
+ mu.RLock()
+ y = x + 1
+ mu.RUnlock()
+ ch <- true
+ }()
+ go func() {
+ mu.RLock()
+ y = x + 2
+ mu.RUnlock()
+ ch <- true
+ }()
+ go func() {
+ mu.RLock()
+ y = x + 3
+ mu.RUnlock()
+ ch <- true
+ }()
+ <-ch
+ <-ch
+ <-ch
+ <-ch
+ _ = y
+}
+
+func TestNoRaceRWMutexMultipleReaders(t *testing.T) {
+ var mu sync.RWMutex
+ x := int64(0)
+ ch := make(chan bool, 4)
+ go func() {
+ mu.Lock()
+ defer mu.Unlock()
+ x = 2
+ ch <- true
+ }()
+ go func() {
+ mu.RLock()
+ y := x + 1
+ _ = y
+ mu.RUnlock()
+ ch <- true
+ }()
+ go func() {
+ mu.RLock()
+ y := x + 2
+ _ = y
+ mu.RUnlock()
+ ch <- true
+ }()
+ go func() {
+ mu.RLock()
+ y := x + 3
+ _ = y
+ mu.RUnlock()
+ ch <- true
+ }()
+ <-ch
+ <-ch
+ <-ch
+ <-ch
+}
+
+func TestNoRaceRWMutexTransitive(t *testing.T) {
+ var mu sync.RWMutex
+ x := int64(0)
+ ch := make(chan bool, 2)
+ go func() {
+ mu.RLock()
+ _ = x
+ mu.RUnlock()
+ ch <- true
+ }()
+ go func() {
+ time.Sleep(1e7)
+ mu.RLock()
+ _ = x
+ mu.RUnlock()
+ ch <- true
+ }()
+ time.Sleep(2e7)
+ mu.Lock()
+ x = 42
+ mu.Unlock()
+ <-ch
+ <-ch
+}
diff --git a/src/runtime/race/testdata/select_test.go b/src/runtime/race/testdata/select_test.go
new file mode 100644
index 0000000..9a43f9b
--- /dev/null
+++ b/src/runtime/race/testdata/select_test.go
@@ -0,0 +1,293 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "runtime"
+ "testing"
+)
+
+func TestNoRaceSelect1(t *testing.T) {
+ var x int
+ _ = x
+ compl := make(chan bool)
+ c := make(chan bool)
+ c1 := make(chan bool)
+
+ go func() {
+ x = 1
+ // At least two channels are needed because
+ // otherwise the compiler optimizes select out.
+ // See comment in runtime/select.go:^func selectgo.
+ select {
+ case c <- true:
+ case c1 <- true:
+ }
+ compl <- true
+ }()
+ select {
+ case <-c:
+ case c1 <- true:
+ }
+ x = 2
+ <-compl
+}
+
+func TestNoRaceSelect2(t *testing.T) {
+ var x int
+ _ = x
+ compl := make(chan bool)
+ c := make(chan bool)
+ c1 := make(chan bool)
+ go func() {
+ select {
+ case <-c:
+ case <-c1:
+ }
+ x = 1
+ compl <- true
+ }()
+ x = 2
+ close(c)
+ runtime.Gosched()
+ <-compl
+}
+
+func TestNoRaceSelect3(t *testing.T) {
+ var x int
+ _ = x
+ compl := make(chan bool)
+ c := make(chan bool, 10)
+ c1 := make(chan bool)
+ go func() {
+ x = 1
+ select {
+ case c <- true:
+ case <-c1:
+ }
+ compl <- true
+ }()
+ <-c
+ x = 2
+ <-compl
+}
+
+func TestNoRaceSelect4(t *testing.T) {
+ type Task struct {
+ f func()
+ done chan bool
+ }
+
+ queue := make(chan Task)
+ dummy := make(chan bool)
+
+ go func() {
+ for {
+ select {
+ case t := <-queue:
+ t.f()
+ t.done <- true
+ }
+ }
+ }()
+
+ doit := func(f func()) {
+ done := make(chan bool, 1)
+ select {
+ case queue <- Task{f, done}:
+ case <-dummy:
+ }
+ select {
+ case <-done:
+ case <-dummy:
+ }
+ }
+
+ var x int
+ doit(func() {
+ x = 1
+ })
+ _ = x
+}
+
+func TestNoRaceSelect5(t *testing.T) {
+ test := func(sel, needSched bool) {
+ var x int
+ _ = x
+ ch := make(chan bool)
+ c1 := make(chan bool)
+
+ done := make(chan bool, 2)
+ go func() {
+ if needSched {
+ runtime.Gosched()
+ }
+ // println(1)
+ x = 1
+ if sel {
+ select {
+ case ch <- true:
+ case <-c1:
+ }
+ } else {
+ ch <- true
+ }
+ done <- true
+ }()
+
+ go func() {
+ // println(2)
+ if sel {
+ select {
+ case <-ch:
+ case <-c1:
+ }
+ } else {
+ <-ch
+ }
+ x = 1
+ done <- true
+ }()
+ <-done
+ <-done
+ }
+
+ test(true, true)
+ test(true, false)
+ test(false, true)
+ test(false, false)
+}
+
+func TestRaceSelect1(t *testing.T) {
+ var x int
+ _ = x
+ compl := make(chan bool, 2)
+ c := make(chan bool)
+ c1 := make(chan bool)
+
+ go func() {
+ <-c
+ <-c
+ }()
+ f := func() {
+ select {
+ case c <- true:
+ case c1 <- true:
+ }
+ x = 1
+ compl <- true
+ }
+ go f()
+ go f()
+ <-compl
+ <-compl
+}
+
+func TestRaceSelect2(t *testing.T) {
+ var x int
+ _ = x
+ compl := make(chan bool)
+ c := make(chan bool)
+ c1 := make(chan bool)
+ go func() {
+ x = 1
+ select {
+ case <-c:
+ case <-c1:
+ }
+ compl <- true
+ }()
+ close(c)
+ x = 2
+ <-compl
+}
+
+func TestRaceSelect3(t *testing.T) {
+ var x int
+ _ = x
+ compl := make(chan bool)
+ c := make(chan bool)
+ c1 := make(chan bool)
+ go func() {
+ x = 1
+ select {
+ case c <- true:
+ case c1 <- true:
+ }
+ compl <- true
+ }()
+ x = 2
+ select {
+ case <-c:
+ }
+ <-compl
+}
+
+func TestRaceSelect4(t *testing.T) {
+ done := make(chan bool, 1)
+ var x int
+ go func() {
+ select {
+ default:
+ x = 2
+ }
+ done <- true
+ }()
+ _ = x
+ <-done
+}
+
+// The idea behind this test:
+// there are two variables, access to one
+// of them is synchronized, access to the other
+// is not.
+// Select must (unconditionally) choose the non-synchronized variable
+// thus causing exactly one race.
+// Currently this test doesn't look like it accomplishes
+// this goal.
+func TestRaceSelect5(t *testing.T) {
+ done := make(chan bool, 1)
+ c1 := make(chan bool, 1)
+ c2 := make(chan bool)
+ var x, y int
+ go func() {
+ select {
+ case c1 <- true:
+ x = 1
+ case c2 <- true:
+ y = 1
+ }
+ done <- true
+ }()
+ _ = x
+ _ = y
+ <-done
+}
+
+// select statements may introduce
+// flakiness: whether this test contains
+// a race depends on the scheduling
+// (some may argue that the code contains
+// this race by definition)
+/*
+func TestFlakyDefault(t *testing.T) {
+ var x int
+ c := make(chan bool, 1)
+ done := make(chan bool, 1)
+ go func() {
+ select {
+ case <-c:
+ x = 2
+ default:
+ x = 3
+ }
+ done <- true
+ }()
+ x = 1
+ c <- true
+ _ = x
+ <-done
+}
+*/
diff --git a/src/runtime/race/testdata/slice_test.go b/src/runtime/race/testdata/slice_test.go
new file mode 100644
index 0000000..9009a9a
--- /dev/null
+++ b/src/runtime/race/testdata/slice_test.go
@@ -0,0 +1,608 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "sync"
+ "testing"
+)
+
+func TestRaceSliceRW(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]int, 2)
+ go func() {
+ a[1] = 1
+ ch <- true
+ }()
+ _ = a[1]
+ <-ch
+}
+
+func TestNoRaceSliceRW(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]int, 2)
+ go func() {
+ a[0] = 1
+ ch <- true
+ }()
+ _ = a[1]
+ <-ch
+}
+
+func TestRaceSliceWW(t *testing.T) {
+ a := make([]int, 10)
+ ch := make(chan bool, 1)
+ go func() {
+ a[1] = 1
+ ch <- true
+ }()
+ a[1] = 2
+ <-ch
+}
+
+func TestNoRaceArrayWW(t *testing.T) {
+ var a [5]int
+ ch := make(chan bool, 1)
+ go func() {
+ a[0] = 1
+ ch <- true
+ }()
+ a[1] = 2
+ <-ch
+}
+
+func TestRaceArrayWW(t *testing.T) {
+ var a [5]int
+ ch := make(chan bool, 1)
+ go func() {
+ a[1] = 1
+ ch <- true
+ }()
+ a[1] = 2
+ <-ch
+}
+
+func TestNoRaceSliceWriteLen(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]bool, 1)
+ go func() {
+ a[0] = true
+ ch <- true
+ }()
+ _ = len(a)
+ <-ch
+}
+
+func TestNoRaceSliceWriteCap(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]uint64, 100)
+ go func() {
+ a[50] = 123
+ ch <- true
+ }()
+ _ = cap(a)
+ <-ch
+}
+
+func TestRaceSliceCopyRead(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]int, 10)
+ b := make([]int, 10)
+ go func() {
+ _ = a[5]
+ ch <- true
+ }()
+ copy(a, b)
+ <-ch
+}
+
+func TestNoRaceSliceWriteCopy(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]int, 10)
+ b := make([]int, 10)
+ go func() {
+ a[5] = 1
+ ch <- true
+ }()
+ copy(a[:5], b[:5])
+ <-ch
+}
+
+func TestRaceSliceCopyWrite2(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]int, 10)
+ b := make([]int, 10)
+ go func() {
+ b[5] = 1
+ ch <- true
+ }()
+ copy(a, b)
+ <-ch
+}
+
+func TestRaceSliceCopyWrite3(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]byte, 10)
+ go func() {
+ a[7] = 1
+ ch <- true
+ }()
+ copy(a, "qwertyqwerty")
+ <-ch
+}
+
+func TestNoRaceSliceCopyRead(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]int, 10)
+ b := make([]int, 10)
+ go func() {
+ _ = b[5]
+ ch <- true
+ }()
+ copy(a, b)
+ <-ch
+}
+
+func TestRacePointerSliceCopyRead(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]*int, 10)
+ b := make([]*int, 10)
+ go func() {
+ _ = a[5]
+ ch <- true
+ }()
+ copy(a, b)
+ <-ch
+}
+
+func TestNoRacePointerSliceWriteCopy(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]*int, 10)
+ b := make([]*int, 10)
+ go func() {
+ a[5] = new(int)
+ ch <- true
+ }()
+ copy(a[:5], b[:5])
+ <-ch
+}
+
+func TestRacePointerSliceCopyWrite2(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]*int, 10)
+ b := make([]*int, 10)
+ go func() {
+ b[5] = new(int)
+ ch <- true
+ }()
+ copy(a, b)
+ <-ch
+}
+
+func TestNoRacePointerSliceCopyRead(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]*int, 10)
+ b := make([]*int, 10)
+ go func() {
+ _ = b[5]
+ ch <- true
+ }()
+ copy(a, b)
+ <-ch
+}
+
+func TestNoRaceSliceWriteSlice2(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]float64, 10)
+ go func() {
+ a[2] = 1.0
+ ch <- true
+ }()
+ _ = a[0:5]
+ <-ch
+}
+
+func TestRaceSliceWriteSlice(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]float64, 10)
+ go func() {
+ a[2] = 1.0
+ ch <- true
+ }()
+ a = a[5:10]
+ <-ch
+}
+
+func TestNoRaceSliceWriteSlice(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]float64, 10)
+ go func() {
+ a[2] = 1.0
+ ch <- true
+ }()
+ _ = a[5:10]
+ <-ch
+}
+
+func TestNoRaceSliceLenCap(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]struct{}, 10)
+ go func() {
+ _ = len(a)
+ ch <- true
+ }()
+ _ = cap(a)
+ <-ch
+}
+
+func TestNoRaceStructSlicesRangeWrite(t *testing.T) {
+ type Str struct {
+ a []int
+ b []int
+ }
+ ch := make(chan bool, 1)
+ var s Str
+ s.a = make([]int, 10)
+ s.b = make([]int, 10)
+ go func() {
+ for range s.a {
+ }
+ ch <- true
+ }()
+ s.b[5] = 5
+ <-ch
+}
+
+func TestRaceSliceDifferent(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ s2 := s
+ go func() {
+ s[3] = 3
+ c <- true
+ }()
+ // false negative because s2 is PAUTO w/o PHEAP
+ // so we do not instrument it
+ s2[3] = 3
+ <-c
+}
+
+func TestRaceSliceRangeWrite(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ s[3] = 3
+ c <- true
+ }()
+ for _, v := range s {
+ _ = v
+ }
+ <-c
+}
+
+func TestNoRaceSliceRangeWrite(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ s[3] = 3
+ c <- true
+ }()
+ for range s {
+ }
+ <-c
+}
+
+func TestRaceSliceRangeAppend(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ s = append(s, 3)
+ c <- true
+ }()
+ for range s {
+ }
+ <-c
+}
+
+func TestNoRaceSliceRangeAppend(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ _ = append(s, 3)
+ c <- true
+ }()
+ for range s {
+ }
+ <-c
+}
+
+func TestRaceSliceVarWrite(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ s[3] = 3
+ c <- true
+ }()
+ s = make([]int, 20)
+ <-c
+}
+
+func TestRaceSliceVarRead(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ _ = s[3]
+ c <- true
+ }()
+ s = make([]int, 20)
+ <-c
+}
+
+func TestRaceSliceVarRange(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ for range s {
+ }
+ c <- true
+ }()
+ s = make([]int, 20)
+ <-c
+}
+
+func TestRaceSliceVarAppend(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ _ = append(s, 10)
+ c <- true
+ }()
+ s = make([]int, 20)
+ <-c
+}
+
+func TestRaceSliceVarCopy(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ s2 := make([]int, 10)
+ copy(s, s2)
+ c <- true
+ }()
+ s = make([]int, 20)
+ <-c
+}
+
+func TestRaceSliceVarCopy2(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ s2 := make([]int, 10)
+ copy(s2, s)
+ c <- true
+ }()
+ s = make([]int, 20)
+ <-c
+}
+
+func TestRaceSliceAppend(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10, 20)
+ go func() {
+ _ = append(s, 1)
+ c <- true
+ }()
+ _ = append(s, 2)
+ <-c
+}
+
+func TestRaceSliceAppendWrite(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ _ = append(s, 1)
+ c <- true
+ }()
+ s[0] = 42
+ <-c
+}
+
+func TestRaceSliceAppendSlice(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ go func() {
+ s2 := make([]int, 10)
+ _ = append(s, s2...)
+ c <- true
+ }()
+ s[0] = 42
+ <-c
+}
+
+func TestRaceSliceAppendSlice2(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ s2foobar := make([]int, 10)
+ go func() {
+ _ = append(s, s2foobar...)
+ c <- true
+ }()
+ s2foobar[5] = 42
+ <-c
+}
+
+func TestRaceSliceAppendString(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]byte, 10)
+ go func() {
+ _ = append(s, "qwerty"...)
+ c <- true
+ }()
+ s[0] = 42
+ <-c
+}
+
+func TestRacePointerSliceAppend(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]*int, 10, 20)
+ go func() {
+ _ = append(s, new(int))
+ c <- true
+ }()
+ _ = append(s, new(int))
+ <-c
+}
+
+func TestRacePointerSliceAppendWrite(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]*int, 10)
+ go func() {
+ _ = append(s, new(int))
+ c <- true
+ }()
+ s[0] = new(int)
+ <-c
+}
+
+func TestRacePointerSliceAppendSlice(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]*int, 10)
+ go func() {
+ s2 := make([]*int, 10)
+ _ = append(s, s2...)
+ c <- true
+ }()
+ s[0] = new(int)
+ <-c
+}
+
+func TestRacePointerSliceAppendSlice2(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]*int, 10)
+ s2foobar := make([]*int, 10)
+ go func() {
+ _ = append(s, s2foobar...)
+ c <- true
+ }()
+ println("WRITE:", &s2foobar[5])
+ s2foobar[5] = nil
+ <-c
+}
+
+func TestNoRaceSliceIndexAccess(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ v := 0
+ go func() {
+ _ = v
+ c <- true
+ }()
+ s[v] = 1
+ <-c
+}
+
+func TestNoRaceSliceIndexAccess2(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ v := 0
+ go func() {
+ _ = v
+ c <- true
+ }()
+ _ = s[v]
+ <-c
+}
+
+func TestRaceSliceIndexAccess(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ v := 0
+ go func() {
+ v = 1
+ c <- true
+ }()
+ s[v] = 1
+ <-c
+}
+
+func TestRaceSliceIndexAccess2(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]int, 10)
+ v := 0
+ go func() {
+ v = 1
+ c <- true
+ }()
+ _ = s[v]
+ <-c
+}
+
+func TestRaceSliceByteToString(t *testing.T) {
+ c := make(chan string)
+ s := make([]byte, 10)
+ go func() {
+ c <- string(s)
+ }()
+ s[0] = 42
+ <-c
+}
+
+func TestRaceSliceRuneToString(t *testing.T) {
+ c := make(chan string)
+ s := make([]rune, 10)
+ go func() {
+ c <- string(s)
+ }()
+ s[9] = 42
+ <-c
+}
+
+func TestRaceConcatString(t *testing.T) {
+ s := "hello"
+ c := make(chan string, 1)
+ go func() {
+ c <- s + " world"
+ }()
+ s = "world"
+ <-c
+}
+
+func TestRaceCompareString(t *testing.T) {
+ s1 := "hello"
+ s2 := "world"
+ c := make(chan bool, 1)
+ go func() {
+ c <- s1 == s2
+ }()
+ s1 = s2
+ <-c
+}
+
+func TestRaceSlice3(t *testing.T) {
+ done := make(chan bool)
+ x := make([]int, 10)
+ i := 2
+ go func() {
+ i = 3
+ done <- true
+ }()
+ _ = x[:1:i]
+ <-done
+}
+
+var saved string
+
+func TestRaceSlice4(t *testing.T) {
+ // See issue 36794.
+ data := []byte("hello there")
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ _ = string(data)
+ wg.Done()
+ }()
+ copy(data, data[2:])
+ wg.Wait()
+}
diff --git a/src/runtime/race/testdata/sync_test.go b/src/runtime/race/testdata/sync_test.go
new file mode 100644
index 0000000..b5fcd6c
--- /dev/null
+++ b/src/runtime/race/testdata/sync_test.go
@@ -0,0 +1,202 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestNoRaceCond(t *testing.T) {
+ x := 0
+ _ = x
+ condition := 0
+ var mu sync.Mutex
+ cond := sync.NewCond(&mu)
+ go func() {
+ x = 1
+ mu.Lock()
+ condition = 1
+ cond.Signal()
+ mu.Unlock()
+ }()
+ mu.Lock()
+ for condition != 1 {
+ cond.Wait()
+ }
+ mu.Unlock()
+ x = 2
+}
+
+func TestRaceCond(t *testing.T) {
+ done := make(chan bool)
+ var mu sync.Mutex
+ cond := sync.NewCond(&mu)
+ x := 0
+ _ = x
+ condition := 0
+ go func() {
+ time.Sleep(10 * time.Millisecond) // Enter cond.Wait loop
+ x = 1
+ mu.Lock()
+ condition = 1
+ cond.Signal()
+ mu.Unlock()
+ time.Sleep(10 * time.Millisecond) // Exit cond.Wait loop
+ mu.Lock()
+ x = 3
+ mu.Unlock()
+ done <- true
+ }()
+ mu.Lock()
+ for condition != 1 {
+ cond.Wait()
+ }
+ mu.Unlock()
+ x = 2
+ <-done
+}
+
+// We do not currently automatically
+// parse this test. It is intended that the creation
+// stack is observed manually not to contain
+// off-by-one errors
+func TestRaceAnnounceThreads(t *testing.T) {
+ const N = 7
+ allDone := make(chan bool, N)
+
+ var x int
+ _ = x
+
+ var f, g, h func()
+ f = func() {
+ x = 1
+ go g()
+ go func() {
+ x = 1
+ allDone <- true
+ }()
+ x = 2
+ allDone <- true
+ }
+
+ g = func() {
+ for i := 0; i < 2; i++ {
+ go func() {
+ x = 1
+ allDone <- true
+ }()
+ allDone <- true
+ }
+ }
+
+ h = func() {
+ x = 1
+ x = 2
+ go f()
+ allDone <- true
+ }
+
+ go h()
+
+ for i := 0; i < N; i++ {
+ <-allDone
+ }
+}
+
+func TestNoRaceAfterFunc1(t *testing.T) {
+ i := 2
+ c := make(chan bool)
+ var f func()
+ f = func() {
+ i--
+ if i >= 0 {
+ time.AfterFunc(0, f)
+ } else {
+ c <- true
+ }
+ }
+
+ time.AfterFunc(0, f)
+ <-c
+}
+
+func TestNoRaceAfterFunc2(t *testing.T) {
+ var x int
+ _ = x
+ timer := time.AfterFunc(10, func() {
+ x = 1
+ })
+ defer timer.Stop()
+}
+
+func TestNoRaceAfterFunc3(t *testing.T) {
+ c := make(chan bool, 1)
+ x := 0
+ _ = x
+ time.AfterFunc(1e7, func() {
+ x = 1
+ c <- true
+ })
+ <-c
+}
+
+func TestRaceAfterFunc3(t *testing.T) {
+ c := make(chan bool, 2)
+ x := 0
+ _ = x
+ time.AfterFunc(1e7, func() {
+ x = 1
+ c <- true
+ })
+ time.AfterFunc(2e7, func() {
+ x = 2
+ c <- true
+ })
+ <-c
+ <-c
+}
+
+// This test's output is intended to be
+// observed manually. One should check
+// that goroutine creation stack is
+// comprehensible.
+func TestRaceGoroutineCreationStack(t *testing.T) {
+ var x int
+ _ = x
+ var ch = make(chan bool, 1)
+
+ f1 := func() {
+ x = 1
+ ch <- true
+ }
+ f2 := func() { go f1() }
+ f3 := func() { go f2() }
+ f4 := func() { go f3() }
+
+ go f4()
+ x = 2
+ <-ch
+}
+
+// A nil pointer in a mutex method call should not
+// corrupt the race detector state.
+// Used to hang indefinitely.
+func TestNoRaceNilMutexCrash(t *testing.T) {
+ var mutex sync.Mutex
+ panics := 0
+ defer func() {
+ if x := recover(); x != nil {
+ mutex.Lock()
+ panics++
+ mutex.Unlock()
+ } else {
+ panic("no panic")
+ }
+ }()
+ var othermutex *sync.RWMutex
+ othermutex.RLock()
+}
diff --git a/src/runtime/race/testdata/waitgroup_test.go b/src/runtime/race/testdata/waitgroup_test.go
new file mode 100644
index 0000000..1693373
--- /dev/null
+++ b/src/runtime/race/testdata/waitgroup_test.go
@@ -0,0 +1,360 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "runtime"
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestNoRaceWaitGroup(t *testing.T) {
+ var x int
+ _ = x
+ var wg sync.WaitGroup
+ n := 1
+ for i := 0; i < n; i++ {
+ wg.Add(1)
+ j := i
+ go func() {
+ x = j
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
+
+func TestRaceWaitGroup(t *testing.T) {
+ var x int
+ _ = x
+ var wg sync.WaitGroup
+ n := 2
+ for i := 0; i < n; i++ {
+ wg.Add(1)
+ j := i
+ go func() {
+ x = j
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
+
+func TestNoRaceWaitGroup2(t *testing.T) {
+ var x int
+ _ = x
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ x = 1
+ wg.Done()
+ }()
+ wg.Wait()
+ x = 2
+}
+
+// incrementing counter in Add and locking wg's mutex
+func TestRaceWaitGroupAsMutex(t *testing.T) {
+ var x int
+ _ = x
+ var wg sync.WaitGroup
+ c := make(chan bool, 2)
+ go func() {
+ wg.Wait()
+ time.Sleep(100 * time.Millisecond)
+ wg.Add(+1)
+ x = 1
+ wg.Add(-1)
+ c <- true
+ }()
+ go func() {
+ wg.Wait()
+ time.Sleep(100 * time.Millisecond)
+ wg.Add(+1)
+ x = 2
+ wg.Add(-1)
+ c <- true
+ }()
+ <-c
+ <-c
+}
+
+// Incorrect usage: Add is too late.
+func TestRaceWaitGroupWrongWait(t *testing.T) {
+ c := make(chan bool, 2)
+ var x int
+ _ = x
+ var wg sync.WaitGroup
+ go func() {
+ wg.Add(1)
+ runtime.Gosched()
+ x = 1
+ wg.Done()
+ c <- true
+ }()
+ go func() {
+ wg.Add(1)
+ runtime.Gosched()
+ x = 2
+ wg.Done()
+ c <- true
+ }()
+ wg.Wait()
+ <-c
+ <-c
+}
+
+func TestRaceWaitGroupWrongAdd(t *testing.T) {
+ c := make(chan bool, 2)
+ var wg sync.WaitGroup
+ go func() {
+ wg.Add(1)
+ time.Sleep(100 * time.Millisecond)
+ wg.Done()
+ c <- true
+ }()
+ go func() {
+ wg.Add(1)
+ time.Sleep(100 * time.Millisecond)
+ wg.Done()
+ c <- true
+ }()
+ time.Sleep(50 * time.Millisecond)
+ wg.Wait()
+ <-c
+ <-c
+}
+
+func TestNoRaceWaitGroupMultipleWait(t *testing.T) {
+ c := make(chan bool, 2)
+ var wg sync.WaitGroup
+ go func() {
+ wg.Wait()
+ c <- true
+ }()
+ go func() {
+ wg.Wait()
+ c <- true
+ }()
+ wg.Wait()
+ <-c
+ <-c
+}
+
+func TestNoRaceWaitGroupMultipleWait2(t *testing.T) {
+ c := make(chan bool, 2)
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ wg.Done()
+ wg.Wait()
+ c <- true
+ }()
+ go func() {
+ wg.Done()
+ wg.Wait()
+ c <- true
+ }()
+ wg.Wait()
+ <-c
+ <-c
+}
+
+func TestNoRaceWaitGroupMultipleWait3(t *testing.T) {
+ const P = 3
+ var data [P]int
+ done := make(chan bool, P)
+ var wg sync.WaitGroup
+ wg.Add(P)
+ for p := 0; p < P; p++ {
+ go func(p int) {
+ data[p] = 42
+ wg.Done()
+ }(p)
+ }
+ for p := 0; p < P; p++ {
+ go func() {
+ wg.Wait()
+ for p1 := 0; p1 < P; p1++ {
+ _ = data[p1]
+ }
+ done <- true
+ }()
+ }
+ for p := 0; p < P; p++ {
+ <-done
+ }
+}
+
+// Correct usage but still a race
+func TestRaceWaitGroup2(t *testing.T) {
+ var x int
+ _ = x
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ x = 1
+ wg.Done()
+ }()
+ go func() {
+ x = 2
+ wg.Done()
+ }()
+ wg.Wait()
+}
+
+func TestNoRaceWaitGroupPanicRecover(t *testing.T) {
+ var x int
+ _ = x
+ var wg sync.WaitGroup
+ defer func() {
+ err := recover()
+ if err != "sync: negative WaitGroup counter" {
+ t.Fatalf("Unexpected panic: %#v", err)
+ }
+ x = 2
+ }()
+ x = 1
+ wg.Add(-1)
+}
+
+// TODO: this is actually a panic-synchronization test, not a
+// WaitGroup test. Move it to another *_test file
+// Is it possible to get a race by synchronization via panic?
+func TestNoRaceWaitGroupPanicRecover2(t *testing.T) {
+ var x int
+ _ = x
+ var wg sync.WaitGroup
+ ch := make(chan bool, 1)
+ var f func() = func() {
+ x = 2
+ ch <- true
+ }
+ go func() {
+ defer func() {
+ err := recover()
+ if err != "sync: negative WaitGroup counter" {
+ }
+ go f()
+ }()
+ x = 1
+ wg.Add(-1)
+ }()
+
+ <-ch
+}
+
+func TestNoRaceWaitGroupTransitive(t *testing.T) {
+ x, y := 0, 0
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ x = 42
+ wg.Done()
+ }()
+ go func() {
+ time.Sleep(1e7)
+ y = 42
+ wg.Done()
+ }()
+ wg.Wait()
+ _ = x
+ _ = y
+}
+
+func TestNoRaceWaitGroupReuse(t *testing.T) {
+ const P = 3
+ var data [P]int
+ var wg sync.WaitGroup
+ for try := 0; try < 3; try++ {
+ wg.Add(P)
+ for p := 0; p < P; p++ {
+ go func(p int) {
+ data[p]++
+ wg.Done()
+ }(p)
+ }
+ wg.Wait()
+ for p := 0; p < P; p++ {
+ data[p]++
+ }
+ }
+}
+
+func TestNoRaceWaitGroupReuse2(t *testing.T) {
+ const P = 3
+ var data [P]int
+ var wg sync.WaitGroup
+ for try := 0; try < 3; try++ {
+ wg.Add(P)
+ for p := 0; p < P; p++ {
+ go func(p int) {
+ data[p]++
+ wg.Done()
+ }(p)
+ }
+ done := make(chan bool)
+ go func() {
+ wg.Wait()
+ for p := 0; p < P; p++ {
+ data[p]++
+ }
+ done <- true
+ }()
+ wg.Wait()
+ <-done
+ for p := 0; p < P; p++ {
+ data[p]++
+ }
+ }
+}
+
+func TestRaceWaitGroupReuse(t *testing.T) {
+ const P = 3
+ const T = 3
+ done := make(chan bool, T)
+ var wg sync.WaitGroup
+ for try := 0; try < T; try++ {
+ var data [P]int
+ wg.Add(P)
+ for p := 0; p < P; p++ {
+ go func(p int) {
+ time.Sleep(50 * time.Millisecond)
+ data[p]++
+ wg.Done()
+ }(p)
+ }
+ go func() {
+ wg.Wait()
+ for p := 0; p < P; p++ {
+ data[p]++
+ }
+ done <- true
+ }()
+ time.Sleep(100 * time.Millisecond)
+ wg.Wait()
+ }
+ for try := 0; try < T; try++ {
+ <-done
+ }
+}
+
+func TestNoRaceWaitGroupConcurrentAdd(t *testing.T) {
+ const P = 4
+ waiting := make(chan bool, P)
+ var wg sync.WaitGroup
+ for p := 0; p < P; p++ {
+ go func() {
+ wg.Add(1)
+ waiting <- true
+ wg.Done()
+ }()
+ }
+ for p := 0; p < P; p++ {
+ <-waiting
+ }
+ wg.Wait()
+}
diff --git a/src/runtime/race/timer_test.go b/src/runtime/race/timer_test.go
new file mode 100644
index 0000000..dd59005
--- /dev/null
+++ b/src/runtime/race/timer_test.go
@@ -0,0 +1,33 @@
+// Copyright 2019 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.
+
+//go:build race
+
+package race_test
+
+import (
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestTimers(t *testing.T) {
+ const goroutines = 8
+ var wg sync.WaitGroup
+ wg.Add(goroutines)
+ var mu sync.Mutex
+ for i := 0; i < goroutines; i++ {
+ go func() {
+ defer wg.Done()
+ ticker := time.NewTicker(1)
+ defer ticker.Stop()
+ for c := 0; c < 1000; c++ {
+ <-ticker.C
+ mu.Lock()
+ mu.Unlock()
+ }
+ }()
+ }
+ wg.Wait()
+}