Commit c61d86af authored by Dmitry Vyukov's avatar Dmitry Vyukov

os: give race detector chance to override Exit(0)

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/4371Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
parent 7b2b45e5
...@@ -44,6 +44,14 @@ func Getgroups() ([]int, error) { ...@@ -44,6 +44,14 @@ func Getgroups() ([]int, error) {
// Exit causes the current program to exit with the given status code. // Exit causes the current program to exit with the given status code.
// Conventionally, code zero indicates success, non-zero an error. // Conventionally, code zero indicates success, non-zero an error.
// The program terminates immediately; deferred functions are // The program terminates immediately; deferred functions are not run.
// not run. func Exit(code int) {
func Exit(code int) { syscall.Exit(code) } 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
...@@ -105,6 +105,14 @@ func main() { ...@@ -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 // start forcegc helper goroutine
func init() { func init() {
go forcegchelper() go forcegchelper()
......
...@@ -23,7 +23,11 @@ func TestOutput(t *testing.T) { ...@@ -23,7 +23,11 @@ func TestOutput(t *testing.T) {
t.Fatalf("failed to create temp directory: %v", err) t.Fatalf("failed to create temp directory: %v", err)
} }
defer os.RemoveAll(dir) 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) f, err := os.Create(src)
if err != nil { if err != nil {
t.Fatalf("failed to create file: %v", err) t.Fatalf("failed to create file: %v", err)
...@@ -37,7 +41,7 @@ func TestOutput(t *testing.T) { ...@@ -37,7 +41,7 @@ func TestOutput(t *testing.T) {
t.Fatalf("failed to close file: %v", err) t.Fatalf("failed to close file: %v", err)
} }
// Pass -l to the compiler to test stack traces. // 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. // GODEBUG spoils program output, GOMAXPROCS makes it flaky.
for _, env := range os.Environ() { for _, env := range os.Environ() {
if strings.HasPrefix(env, "GODEBUG=") || if strings.HasPrefix(env, "GODEBUG=") ||
...@@ -58,11 +62,12 @@ func TestOutput(t *testing.T) { ...@@ -58,11 +62,12 @@ func TestOutput(t *testing.T) {
var tests = []struct { var tests = []struct {
name string name string
run string
gorace string gorace string
source string source string
re string re string
}{ }{
{"simple", "atexit_sleep_ms=0", ` {"simple", "run", "atexit_sleep_ms=0", `
package main package main
import "time" import "time"
func main() { func main() {
...@@ -107,7 +112,7 @@ Found 1 data race\(s\) ...@@ -107,7 +112,7 @@ Found 1 data race\(s\)
exit status 66 exit status 66
`}, `},
{"exitcode", "atexit_sleep_ms=0 exitcode=13", ` {"exitcode", "run", "atexit_sleep_ms=0 exitcode=13", `
package main package main
func main() { func main() {
done := make(chan bool) done := make(chan bool)
...@@ -121,7 +126,7 @@ func main() { ...@@ -121,7 +126,7 @@ func main() {
} }
`, `exit status 13`}, `, `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 package main
func main() { func main() {
done := make(chan bool) done := make(chan bool)
...@@ -137,7 +142,7 @@ func main() { ...@@ -137,7 +142,7 @@ func main() {
go:7 \+0x[0-9,a-f]+ 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 package main
func main() { func main() {
done := make(chan bool) done := make(chan bool)
...@@ -153,4 +158,23 @@ func main() { ...@@ -153,4 +158,23 @@ func main() {
================== ==================
exit status 66 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`},
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment