Initial commit: Go 1.23 release state

This commit is contained in:
Vorapol Rinsatitnon
2024-09-21 23:49:08 +10:00
commit 17cd57a668
13231 changed files with 3114330 additions and 0 deletions

17
src/runtime/race/README Normal file
View File

@@ -0,0 +1,17 @@
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.
internal/amd64v1/race_darwin.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.
internal/amd64v1/race_freebsd.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.
internal/amd64v1/race_linux.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.
internal/amd64v1/race_netbsd.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.
internal/amd64v1/race_openbsd.syso built with LLVM fcf6ae2f070eba73074b6ec8d8281e54d29dbeeb and Go 8f2db14cd35bbd674cb2988a508306de6655e425.
internal/amd64v1/race_windows.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.
internal/amd64v3/race_linux.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.
race_darwin_arm64.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.
race_linux_arm64.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.
race_linux_ppc64le.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.
race_linux_s390x.syso built with LLVM 51bfeff0e4b0757ff773da6882f4d538996c9b04 and Go e7d582b55dda36e76ce4d0ce770139ca0915b7c5.

11
src/runtime/race/doc.go Normal file
View File

@@ -0,0 +1,11 @@
// 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
//go:generate ./mkcgo.sh

View File

@@ -0,0 +1,10 @@
// Copyright 2022 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.
// This package holds the race detector .syso for
// amd64 architectures with GOAMD64<v3.
//go:build amd64 && ((linux && !amd64.v3) || darwin || freebsd || netbsd || openbsd || windows)
package amd64v1

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,10 @@
// Copyright 2022 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.
// This package holds the race detector .syso for
// amd64 architectures with GOAMD64>=v3.
//go:build amd64 && linux && amd64.v3
package amd64v3

Binary file not shown.

20
src/runtime/race/mkcgo.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
hdr='
// Copyright 2022 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 generated by mkcgo.sh. DO NOT EDIT.
//go:build race
'
convert() {
(echo "$hdr"; go tool cgo -dynpackage race -dynimport $1) | gofmt
}
convert race_darwin_arm64.syso >race_darwin_arm64.go
convert internal/amd64v1/race_darwin.syso >race_darwin_amd64.go

View File

@@ -0,0 +1,480 @@
// 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\)
.*testing.go:.*: race detected during execution of test
.*main_test.go:14: true
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]+
==================`}},
// Test symbolizing wrappers. Both (*T).f and main.gowrap1 are wrappers.
// go.dev/issue/60245
{"wrappersym", "run", "", "atexit_sleep_ms=0", `
package main
import "sync"
var wg sync.WaitGroup
var x int
func main() {
f := (*T).f
wg.Add(2)
go f(new(T))
f(new(T))
wg.Wait()
}
type T struct{}
func (t T) f() {
x = 42
wg.Done()
}
`, []string{`==================
WARNING: DATA RACE
Write at 0x[0-9,a-f]+ by goroutine [0-9]:
main\.T\.f\(\)
.*/main.go:15 \+0x[0-9,a-f]+
main\.\(\*T\)\.f\(\)
<autogenerated>:1 \+0x[0-9,a-f]+
main\.main\.gowrap1\(\)
.*/main.go:9 \+0x[0-9,a-f]+
Previous write at 0x[0-9,a-f]+ by main goroutine:
main\.T\.f\(\)
.*/main.go:15 \+0x[0-9,a-f]+
main\.\(\*T\)\.f\(\)
<autogenerated>:1 \+0x[0-9,a-f]+
main\.main\(\)
.*/main.go:10 \+0x[0-9,a-f]+
`}},
}

20
src/runtime/race/race.go Normal file
View File

@@ -0,0 +1,20 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build race && ((linux && (amd64 || arm64 || ppc64le || s390x)) || ((freebsd || netbsd || openbsd || windows) && 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.
// On darwin we always use system DLLs to create threads,
// so we use race_darwin_$GOARCH.go to provide the syso-derived
// symbol information without needing to invoke cgo.
// This allows -race to be used on Mac systems without a C toolchain.
// void __race_unused_func(void);
import "C"

View File

@@ -0,0 +1,108 @@
// Copyright 2022 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 generated by mkcgo.sh. DO NOT EDIT.
//go:build race
package race
//go:cgo_import_dynamic _Block_object_assign _Block_object_assign ""
//go:cgo_import_dynamic _Block_object_dispose _Block_object_dispose ""
//go:cgo_import_dynamic _NSConcreteStackBlock _NSConcreteStackBlock ""
//go:cgo_import_dynamic _NSGetArgv _NSGetArgv ""
//go:cgo_import_dynamic _NSGetEnviron _NSGetEnviron ""
//go:cgo_import_dynamic _NSGetExecutablePath _NSGetExecutablePath ""
//go:cgo_import_dynamic __bzero __bzero ""
//go:cgo_import_dynamic __error __error ""
//go:cgo_import_dynamic __fork __fork ""
//go:cgo_import_dynamic __mmap __mmap ""
//go:cgo_import_dynamic __munmap __munmap ""
//go:cgo_import_dynamic __stack_chk_fail __stack_chk_fail ""
//go:cgo_import_dynamic __stack_chk_guard __stack_chk_guard ""
//go:cgo_import_dynamic _dyld_get_image_header _dyld_get_image_header ""
//go:cgo_import_dynamic _dyld_get_image_name _dyld_get_image_name ""
//go:cgo_import_dynamic _dyld_get_image_vmaddr_slide _dyld_get_image_vmaddr_slide ""
//go:cgo_import_dynamic _dyld_get_shared_cache_range _dyld_get_shared_cache_range ""
//go:cgo_import_dynamic _dyld_get_shared_cache_uuid _dyld_get_shared_cache_uuid ""
//go:cgo_import_dynamic _dyld_image_count _dyld_image_count ""
//go:cgo_import_dynamic _exit _exit ""
//go:cgo_import_dynamic _sanitizer_internal_memcpy _sanitizer_internal_memcpy ""
//go:cgo_import_dynamic _sanitizer_internal_memmove _sanitizer_internal_memmove ""
//go:cgo_import_dynamic _sanitizer_internal_memset _sanitizer_internal_memset ""
//go:cgo_import_dynamic abort abort ""
//go:cgo_import_dynamic arc4random_buf arc4random_buf ""
//go:cgo_import_dynamic close close ""
//go:cgo_import_dynamic dlsym dlsym ""
//go:cgo_import_dynamic dup dup ""
//go:cgo_import_dynamic dup2 dup2 ""
//go:cgo_import_dynamic dyld_shared_cache_iterate_text dyld_shared_cache_iterate_text ""
//go:cgo_import_dynamic execve execve ""
//go:cgo_import_dynamic exit exit ""
//go:cgo_import_dynamic fstat$INODE64 fstat$INODE64 ""
//go:cgo_import_dynamic ftruncate ftruncate ""
//go:cgo_import_dynamic getpid getpid ""
//go:cgo_import_dynamic getrlimit getrlimit ""
//go:cgo_import_dynamic gettimeofday gettimeofday ""
//go:cgo_import_dynamic getuid getuid ""
//go:cgo_import_dynamic grantpt grantpt ""
//go:cgo_import_dynamic ioctl ioctl ""
//go:cgo_import_dynamic isatty isatty ""
//go:cgo_import_dynamic lstat$INODE64 lstat$INODE64 ""
//go:cgo_import_dynamic mach_absolute_time mach_absolute_time ""
//go:cgo_import_dynamic mach_task_self_ mach_task_self_ ""
//go:cgo_import_dynamic mach_timebase_info mach_timebase_info ""
//go:cgo_import_dynamic mach_vm_region_recurse mach_vm_region_recurse ""
//go:cgo_import_dynamic madvise madvise ""
//go:cgo_import_dynamic malloc_num_zones malloc_num_zones ""
//go:cgo_import_dynamic malloc_zones malloc_zones ""
//go:cgo_import_dynamic memcpy memcpy ""
//go:cgo_import_dynamic memset_pattern16 memset_pattern16 ""
//go:cgo_import_dynamic mkdir mkdir ""
//go:cgo_import_dynamic mprotect mprotect ""
//go:cgo_import_dynamic open open ""
//go:cgo_import_dynamic pipe pipe ""
//go:cgo_import_dynamic posix_openpt posix_openpt ""
//go:cgo_import_dynamic posix_spawn posix_spawn ""
//go:cgo_import_dynamic posix_spawn_file_actions_addclose posix_spawn_file_actions_addclose ""
//go:cgo_import_dynamic posix_spawn_file_actions_adddup2 posix_spawn_file_actions_adddup2 ""
//go:cgo_import_dynamic posix_spawn_file_actions_destroy posix_spawn_file_actions_destroy ""
//go:cgo_import_dynamic posix_spawn_file_actions_init posix_spawn_file_actions_init ""
//go:cgo_import_dynamic posix_spawnattr_destroy posix_spawnattr_destroy ""
//go:cgo_import_dynamic posix_spawnattr_init posix_spawnattr_init ""
//go:cgo_import_dynamic posix_spawnattr_setflags posix_spawnattr_setflags ""
//go:cgo_import_dynamic pthread_attr_getstack pthread_attr_getstack ""
//go:cgo_import_dynamic pthread_create pthread_create ""
//go:cgo_import_dynamic pthread_get_stackaddr_np pthread_get_stackaddr_np ""
//go:cgo_import_dynamic pthread_get_stacksize_np pthread_get_stacksize_np ""
//go:cgo_import_dynamic pthread_getspecific pthread_getspecific ""
//go:cgo_import_dynamic pthread_introspection_hook_install pthread_introspection_hook_install ""
//go:cgo_import_dynamic pthread_join pthread_join ""
//go:cgo_import_dynamic pthread_self pthread_self ""
//go:cgo_import_dynamic pthread_sigmask pthread_sigmask ""
//go:cgo_import_dynamic pthread_threadid_np pthread_threadid_np ""
//go:cgo_import_dynamic read read ""
//go:cgo_import_dynamic readlink readlink ""
//go:cgo_import_dynamic realpath$DARWIN_EXTSN realpath$DARWIN_EXTSN ""
//go:cgo_import_dynamic rename rename ""
//go:cgo_import_dynamic sched_yield sched_yield ""
//go:cgo_import_dynamic setrlimit setrlimit ""
//go:cgo_import_dynamic sigaction sigaction ""
//go:cgo_import_dynamic stat$INODE64 stat$INODE64 ""
//go:cgo_import_dynamic sysconf sysconf ""
//go:cgo_import_dynamic sysctl sysctl ""
//go:cgo_import_dynamic sysctlbyname sysctlbyname ""
//go:cgo_import_dynamic task_info task_info ""
//go:cgo_import_dynamic tcgetattr tcgetattr ""
//go:cgo_import_dynamic tcsetattr tcsetattr ""
//go:cgo_import_dynamic unlink unlink ""
//go:cgo_import_dynamic unlockpt unlockpt ""
//go:cgo_import_dynamic usleep usleep ""
//go:cgo_import_dynamic vm_region_64 vm_region_64 ""
//go:cgo_import_dynamic vm_region_recurse_64 vm_region_recurse_64 ""
//go:cgo_import_dynamic waitpid waitpid ""
//go:cgo_import_dynamic write write ""
//go:cgo_import_dynamic memcpy memcpy ""
//go:cgo_import_dynamic memmove memmove ""
//go:cgo_import_dynamic memset memset ""

View File

@@ -0,0 +1,108 @@
// Copyright 2022 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 generated by mkcgo.sh. DO NOT EDIT.
//go:build race
package race
//go:cgo_import_dynamic _Block_object_assign _Block_object_assign ""
//go:cgo_import_dynamic _Block_object_dispose _Block_object_dispose ""
//go:cgo_import_dynamic _NSConcreteStackBlock _NSConcreteStackBlock ""
//go:cgo_import_dynamic _NSGetArgv _NSGetArgv ""
//go:cgo_import_dynamic _NSGetEnviron _NSGetEnviron ""
//go:cgo_import_dynamic _NSGetExecutablePath _NSGetExecutablePath ""
//go:cgo_import_dynamic __error __error ""
//go:cgo_import_dynamic __fork __fork ""
//go:cgo_import_dynamic __mmap __mmap ""
//go:cgo_import_dynamic __munmap __munmap ""
//go:cgo_import_dynamic __stack_chk_fail __stack_chk_fail ""
//go:cgo_import_dynamic __stack_chk_guard __stack_chk_guard ""
//go:cgo_import_dynamic _dyld_get_image_header _dyld_get_image_header ""
//go:cgo_import_dynamic _dyld_get_image_name _dyld_get_image_name ""
//go:cgo_import_dynamic _dyld_get_image_vmaddr_slide _dyld_get_image_vmaddr_slide ""
//go:cgo_import_dynamic _dyld_get_shared_cache_range _dyld_get_shared_cache_range ""
//go:cgo_import_dynamic _dyld_get_shared_cache_uuid _dyld_get_shared_cache_uuid ""
//go:cgo_import_dynamic _dyld_image_count _dyld_image_count ""
//go:cgo_import_dynamic _exit _exit ""
//go:cgo_import_dynamic _sanitizer_internal_memcpy _sanitizer_internal_memcpy ""
//go:cgo_import_dynamic _sanitizer_internal_memmove _sanitizer_internal_memmove ""
//go:cgo_import_dynamic _sanitizer_internal_memset _sanitizer_internal_memset ""
//go:cgo_import_dynamic abort abort ""
//go:cgo_import_dynamic arc4random_buf arc4random_buf ""
//go:cgo_import_dynamic bzero bzero ""
//go:cgo_import_dynamic close close ""
//go:cgo_import_dynamic dlsym dlsym ""
//go:cgo_import_dynamic dup dup ""
//go:cgo_import_dynamic dup2 dup2 ""
//go:cgo_import_dynamic dyld_shared_cache_iterate_text dyld_shared_cache_iterate_text ""
//go:cgo_import_dynamic execve execve ""
//go:cgo_import_dynamic exit exit ""
//go:cgo_import_dynamic fstat fstat ""
//go:cgo_import_dynamic ftruncate ftruncate ""
//go:cgo_import_dynamic getpid getpid ""
//go:cgo_import_dynamic getrlimit getrlimit ""
//go:cgo_import_dynamic gettimeofday gettimeofday ""
//go:cgo_import_dynamic getuid getuid ""
//go:cgo_import_dynamic grantpt grantpt ""
//go:cgo_import_dynamic ioctl ioctl ""
//go:cgo_import_dynamic isatty isatty ""
//go:cgo_import_dynamic lstat lstat ""
//go:cgo_import_dynamic mach_absolute_time mach_absolute_time ""
//go:cgo_import_dynamic mach_task_self_ mach_task_self_ ""
//go:cgo_import_dynamic mach_timebase_info mach_timebase_info ""
//go:cgo_import_dynamic mach_vm_region_recurse mach_vm_region_recurse ""
//go:cgo_import_dynamic madvise madvise ""
//go:cgo_import_dynamic malloc_num_zones malloc_num_zones ""
//go:cgo_import_dynamic malloc_zones malloc_zones ""
//go:cgo_import_dynamic memcpy memcpy ""
//go:cgo_import_dynamic memset_pattern16 memset_pattern16 ""
//go:cgo_import_dynamic mkdir mkdir ""
//go:cgo_import_dynamic mprotect mprotect ""
//go:cgo_import_dynamic open open ""
//go:cgo_import_dynamic pipe pipe ""
//go:cgo_import_dynamic posix_openpt posix_openpt ""
//go:cgo_import_dynamic posix_spawn posix_spawn ""
//go:cgo_import_dynamic posix_spawn_file_actions_addclose posix_spawn_file_actions_addclose ""
//go:cgo_import_dynamic posix_spawn_file_actions_adddup2 posix_spawn_file_actions_adddup2 ""
//go:cgo_import_dynamic posix_spawn_file_actions_destroy posix_spawn_file_actions_destroy ""
//go:cgo_import_dynamic posix_spawn_file_actions_init posix_spawn_file_actions_init ""
//go:cgo_import_dynamic posix_spawnattr_destroy posix_spawnattr_destroy ""
//go:cgo_import_dynamic posix_spawnattr_init posix_spawnattr_init ""
//go:cgo_import_dynamic posix_spawnattr_setflags posix_spawnattr_setflags ""
//go:cgo_import_dynamic pthread_attr_getstack pthread_attr_getstack ""
//go:cgo_import_dynamic pthread_create pthread_create ""
//go:cgo_import_dynamic pthread_get_stackaddr_np pthread_get_stackaddr_np ""
//go:cgo_import_dynamic pthread_get_stacksize_np pthread_get_stacksize_np ""
//go:cgo_import_dynamic pthread_getspecific pthread_getspecific ""
//go:cgo_import_dynamic pthread_introspection_hook_install pthread_introspection_hook_install ""
//go:cgo_import_dynamic pthread_join pthread_join ""
//go:cgo_import_dynamic pthread_self pthread_self ""
//go:cgo_import_dynamic pthread_sigmask pthread_sigmask ""
//go:cgo_import_dynamic pthread_threadid_np pthread_threadid_np ""
//go:cgo_import_dynamic read read ""
//go:cgo_import_dynamic readlink readlink ""
//go:cgo_import_dynamic realpath$DARWIN_EXTSN realpath$DARWIN_EXTSN ""
//go:cgo_import_dynamic rename rename ""
//go:cgo_import_dynamic sched_yield sched_yield ""
//go:cgo_import_dynamic setrlimit setrlimit ""
//go:cgo_import_dynamic sigaction sigaction ""
//go:cgo_import_dynamic stat stat ""
//go:cgo_import_dynamic sysconf sysconf ""
//go:cgo_import_dynamic sysctl sysctl ""
//go:cgo_import_dynamic sysctlbyname sysctlbyname ""
//go:cgo_import_dynamic task_info task_info ""
//go:cgo_import_dynamic tcgetattr tcgetattr ""
//go:cgo_import_dynamic tcsetattr tcsetattr ""
//go:cgo_import_dynamic unlink unlink ""
//go:cgo_import_dynamic unlockpt unlockpt ""
//go:cgo_import_dynamic usleep usleep ""
//go:cgo_import_dynamic vm_region_64 vm_region_64 ""
//go:cgo_import_dynamic vm_region_recurse_64 vm_region_recurse_64 ""
//go:cgo_import_dynamic waitpid waitpid ""
//go:cgo_import_dynamic write write ""
//go:cgo_import_dynamic memcpy memcpy ""
//go:cgo_import_dynamic memmove memmove ""
//go:cgo_import_dynamic memset memset ""

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,65 @@
// 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)
}
}
func TestAtomicPageBoundary(t *testing.T) {
// Test that atomic access near (but not cross) a page boundary
// doesn't fault. See issue 60825.
// Mmap two pages of memory, and make the second page inaccessible,
// so we have an address at the end of a page.
pagesize := syscall.Getpagesize()
b, err := syscall.Mmap(0, 0, 2*pagesize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
if err != nil {
t.Fatalf("mmap failed %s", err)
}
defer syscall.Munmap(b)
err = syscall.Mprotect(b[pagesize:], syscall.PROT_NONE)
if err != nil {
t.Fatalf("mprotect high failed %s\n", err)
}
// This should not fault.
a := (*uint32)(unsafe.Pointer(&b[pagesize-4]))
atomic.StoreUint32(a, 1)
if x := atomic.LoadUint32(a); x != 1 {
t.Fatalf("bad atomic value: %v, want 1", x)
}
if x := atomic.AddUint32(a, 1); x != 2 {
t.Fatalf("bad atomic value: %v, want 2", x)
}
}

View File

@@ -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)
}

View File

@@ -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)
}
defer syscall.Munmap(data)
p := (*uint32)(unsafe.Pointer(&data[0]))
atomic.AddUint32(p, 1)
(*p)++
if *p != 2 {
t.Fatalf("data[0] = %v, expect 2", *p)
}
}

View File

@@ -0,0 +1,9 @@
// Copyright 2022 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 && !amd64.v3) || darwin || freebsd || netbsd || openbsd || windows
package race
import _ "runtime/race/internal/amd64v1"

View File

@@ -0,0 +1,9 @@
// Copyright 2022 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 && amd64.v3
package race
import _ "runtime/race/internal/amd64v3"

View File

@@ -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)
}
}

View File

@@ -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 (
"fmt"
"reflect"
"runtime"
"strings"
"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 strings.Builder
for i := 0; i < N; i++ {
fmt.Fprintf(&buf, "%v\n", out[i])
}
t.Fatalf("consistent goroutine execution order:\n%v", buf.String())
}

View File

@@ -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)
}
}
}

325
src/runtime/race/testdata/atomic_test.go vendored Normal file
View File

@@ -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)
}

21
src/runtime/race/testdata/cgo_test.go vendored Normal file
View File

@@ -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)
}
}

View File

@@ -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
}

787
src/runtime/race/testdata/chan_test.go vendored Normal file
View File

@@ -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 TestNoRaceElemSize0(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
}

186
src/runtime/race/testdata/comp_test.go vendored Normal file
View File

@@ -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
}

View File

@@ -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
}

75
src/runtime/race/testdata/io_test.go vendored Normal file
View File

@@ -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++
}

View File

@@ -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])))
}

View File

@@ -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
}

View File

@@ -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 {
}
}

335
src/runtime/race/testdata/map_test.go vendored Normal file
View File

@@ -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
}

2132
src/runtime/race/testdata/mop_test.go vendored Normal file

File diff suppressed because it is too large Load Diff

150
src/runtime/race/testdata/mutex_test.go vendored Normal file
View File

@@ -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
}

47
src/runtime/race/testdata/pool_test.go vendored Normal file
View File

@@ -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
}
}

View File

@@ -0,0 +1,77 @@
// Copyright 2024 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 goexperiment.rangefunc
package race_test
import (
"runtime"
"sync/atomic"
"testing"
)
type Seq2[T1, T2 any] func(yield func(T1, T2) bool)
// ofSliceIndex returns a Seq over the elements of s. It is equivalent
// to range s, except that it splits s into two halves and iterates
// in two separate goroutines. This is racy if yield is racy, and yield
// will be racy if it contains an early exit.
func ofSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
return func(yield func(int, T) bool) {
c := make(chan bool, 2)
var done atomic.Bool
go func() {
for i := 0; i < len(s)/2; i++ {
if !done.Load() && !yield(i, s[i]) {
done.Store(true)
c <- false
}
}
c <- true
}()
go func() {
for i := len(s) / 2; i < len(s); i++ {
if !done.Load() && !yield(i, s[i]) {
done.Store(true)
c <- false
}
}
c <- true
return
}()
if !<-c {
return
}
<-c
}
}
// foo is racy, or not, depending on the value of v
// (0-4 == racy, otherwise, not racy).
func foo(v int) int64 {
var asum atomic.Int64
for i, x := range ofSliceIndex([]int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
if i%5 == v {
break
}
asum.Add(x) // don't race on asum
runtime.Gosched()
}
return 100 + asum.Load()
}
// TestRaceRangeFuncIterator races because x%5 can be equal to 4,
// therefore foo can early exit.
func TestRaceRangeFuncIterator(t *testing.T) {
x := foo(4)
t.Logf("foo(4)=%d", x)
}
// TestNoRaceRangeFuncIterator does not race because x%5 is never 5,
// therefore foo's loop will not exit early, and this it will not race.
func TestNoRaceRangeFuncIterator(t *testing.T) {
x := foo(5)
t.Logf("foo(5)=%d", x)
}

View File

@@ -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
}

View File

@@ -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 {
}
}

View File

@@ -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
}

293
src/runtime/race/testdata/select_test.go vendored Normal file
View File

@@ -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
}
*/

608
src/runtime/race/testdata/slice_test.go vendored Normal file
View File

@@ -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()
}

202
src/runtime/race/testdata/sync_test.go vendored Normal file
View File

@@ -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()
}

116
src/runtime/race/testdata/time_test.go vendored Normal file
View File

@@ -0,0 +1,116 @@
// 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 (
"testing"
"time"
)
func TestNoRaceAfterFunc(_ *testing.T) {
v := 0
_ = v
c := make(chan int)
f := func() {
v = 1
c <- 0
}
v = 2
time.AfterFunc(1, f)
<-c
v = 3
}
func TestNoRaceAfterFuncReset(_ *testing.T) {
v := 0
_ = v
c := make(chan int)
f := func() {
v = 1
c <- 0
}
t := time.AfterFunc(time.Hour, f)
t.Stop()
v = 2
t.Reset(1)
<-c
v = 3
}
func TestNoRaceTimer(_ *testing.T) {
v := 0
_ = v
c := make(chan int)
f := func() {
v = 1
c <- 0
}
v = 2
t := time.NewTimer(1)
go func() {
<-t.C
f()
}()
<-c
v = 3
}
func TestNoRaceTimerReset(_ *testing.T) {
v := 0
_ = v
c := make(chan int)
f := func() {
v = 1
c <- 0
}
t := time.NewTimer(time.Hour)
go func() {
<-t.C
f()
}()
t.Stop()
v = 2
t.Reset(1)
<-c
v = 3
}
func TestNoRaceTicker(_ *testing.T) {
v := 0
_ = v
c := make(chan int)
f := func() {
v = 1
c <- 0
}
v = 2
t := time.NewTicker(1)
go func() {
<-t.C
f()
}()
<-c
v = 3
}
func TestNoRaceTickerReset(_ *testing.T) {
v := 0
_ = v
c := make(chan int)
f := func() {
v = 1
c <- 0
}
t := time.NewTicker(time.Hour)
go func() {
<-t.C
f()
}()
t.Stop()
v = 2
t.Reset(1)
<-c
v = 3
}

View File

@@ -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()
}

View File

@@ -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()
}