]> Cypherpunks repositories - gostls13.git/commitdiff
os: give race detector chance to override Exit(0)
authorDmitry Vyukov <dvyukov@google.com>
Tue, 10 Feb 2015 14:26:26 +0000 (17:26 +0300)
committerDmitry Vyukov <dvyukov@google.com>
Sat, 28 Mar 2015 12:42:37 +0000 (12:42 +0000)
Racy tests do not fail currently, they do os.Exit(0).
So if you run go test without -v, you won't even notice.
This was probably introduced with testing.TestMain.

Racy programs do not have the right to finish successfully.

Change-Id: Id133d7424f03d90d438bc3478528683dd02b8846
Reviewed-on: https://go-review.googlesource.com/4371
Reviewed-by: Russ Cox <rsc@golang.org>
src/os/proc.go
src/runtime/proc.go
src/runtime/race/output_test.go

index 774f09900ec58aac3c3897012bd545aa5247d81e..33a8b26f78d3db7779b23dc2e883f6ef9c094311 100644 (file)
@@ -44,6 +44,14 @@ func Getgroups() ([]int, error) {
 
 // Exit causes the current program to exit with the given status code.
 // Conventionally, code zero indicates success, non-zero an error.
-// The program terminates immediately; deferred functions are
-// not run.
-func Exit(code int) { syscall.Exit(code) }
+// The program terminates immediately; deferred functions are not run.
+func Exit(code int) {
+       if code == 0 {
+               // Give race detector a chance to fail the program.
+               // Racy programs do not have the right to finish successfully.
+               runtime_beforeExit()
+       }
+       syscall.Exit(code)
+}
+
+func runtime_beforeExit() // implemented in runtime
index 2953dd6a2ba6e2bd4c208411ef0eb8ab0d9de799..edab9bfdd62e32cfb18c6ac8ab0aa6b024dc158e 100644 (file)
@@ -105,6 +105,14 @@ func main() {
        }
 }
 
+// os_beforeExit is called from os.Exit(0).
+//go:linkname os_beforeExit os.runtime_beforeExit
+func os_beforeExit() {
+       if raceenabled {
+               racefini()
+       }
+}
+
 // start forcegc helper goroutine
 func init() {
        go forcegchelper()
index d2303f7afaaab885f3a1dd8a7ade9663c5866791..a9f9f0fbd5deb485c35338545b79c1a4cabe65e3 100644 (file)
@@ -23,7 +23,11 @@ func TestOutput(t *testing.T) {
                        t.Fatalf("failed to create temp directory: %v", err)
                }
                defer os.RemoveAll(dir)
-               src := filepath.Join(dir, "main.go")
+               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)
@@ -37,7 +41,7 @@ func TestOutput(t *testing.T) {
                        t.Fatalf("failed to close file: %v", err)
                }
                // Pass -l to the compiler to test stack traces.
-               cmd := exec.Command("go", "run", "-race", "-gcflags=-l", src)
+               cmd := exec.Command("go", test.run, "-race", "-gcflags=-l", src)
                // GODEBUG spoils program output, GOMAXPROCS makes it flaky.
                for _, env := range os.Environ() {
                        if strings.HasPrefix(env, "GODEBUG=") ||
@@ -58,11 +62,12 @@ func TestOutput(t *testing.T) {
 
 var tests = []struct {
        name   string
+       run    string
        gorace string
        source string
        re     string
 }{
-       {"simple", "atexit_sleep_ms=0", `
+       {"simple", "run", "atexit_sleep_ms=0", `
 package main
 import "time"
 func main() {
@@ -107,7 +112,7 @@ Found 1 data race\(s\)
 exit status 66
 `},
 
-       {"exitcode", "atexit_sleep_ms=0 exitcode=13", `
+       {"exitcode", "run", "atexit_sleep_ms=0 exitcode=13", `
 package main
 func main() {
        done := make(chan bool)
@@ -121,7 +126,7 @@ func main() {
 }
 `, `exit status 13`},
 
-       {"strip_path_prefix", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
+       {"strip_path_prefix", "run", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
 package main
 func main() {
        done := make(chan bool)
@@ -137,7 +142,7 @@ func main() {
       go:7 \+0x[0-9,a-f]+
 `},
 
-       {"halt_on_error", "atexit_sleep_ms=0 halt_on_error=1", `
+       {"halt_on_error", "run", "atexit_sleep_ms=0 halt_on_error=1", `
 package main
 func main() {
        done := make(chan bool)
@@ -153,4 +158,23 @@ func main() {
 ==================
 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
+       go func() {
+               x = 42
+               done <- true
+       }()
+       x = 43
+       <-done
+}
+`, `
+==================
+PASS
+Found 1 data race\(s\)
+FAIL`},
 }