github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/runtime/race/race_test.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build race 6 7 // This program is used to verify the race detector 8 // by running the tests and parsing their output. 9 // It does not check stack correctness, completeness or anything else: 10 // it merely verifies that if a test is expected to be racy 11 // then the race is detected. 12 package race_test 13 14 import ( 15 "bufio" 16 "bytes" 17 "fmt" 18 "io" 19 "log" 20 "math/rand" 21 "os" 22 "os/exec" 23 "path/filepath" 24 "strings" 25 "sync" 26 "sync/atomic" 27 "testing" 28 ) 29 30 var ( 31 passedTests = 0 32 totalTests = 0 33 falsePos = 0 34 falseNeg = 0 35 failingPos = 0 36 failingNeg = 0 37 failed = false 38 ) 39 40 const ( 41 visibleLen = 40 42 testPrefix = "=== RUN Test" 43 ) 44 45 func TestRace(t *testing.T) { 46 testOutput, err := runTests() 47 if err != nil { 48 t.Fatalf("Failed to run tests: %v\n%v", err, string(testOutput)) 49 } 50 reader := bufio.NewReader(bytes.NewReader(testOutput)) 51 52 funcName := "" 53 var tsanLog []string 54 for { 55 s, err := nextLine(reader) 56 if err != nil { 57 fmt.Printf("%s\n", processLog(funcName, tsanLog)) 58 break 59 } 60 if strings.HasPrefix(s, testPrefix) { 61 fmt.Printf("%s\n", processLog(funcName, tsanLog)) 62 tsanLog = make([]string, 0, 100) 63 funcName = s[len(testPrefix):] 64 } else { 65 tsanLog = append(tsanLog, s) 66 } 67 } 68 69 if totalTests == 0 { 70 t.Fatalf("failed to parse test output") 71 } 72 fmt.Printf("\nPassed %d of %d tests (%.02f%%, %d+, %d-)\n", 73 passedTests, totalTests, 100*float64(passedTests)/float64(totalTests), falsePos, falseNeg) 74 fmt.Printf("%d expected failures (%d has not fail)\n", failingPos+failingNeg, failingNeg) 75 if failed { 76 t.Fail() 77 } 78 } 79 80 // nextLine is a wrapper around bufio.Reader.ReadString. 81 // It reads a line up to the next '\n' character. Error 82 // is non-nil if there are no lines left, and nil 83 // otherwise. 84 func nextLine(r *bufio.Reader) (string, error) { 85 s, err := r.ReadString('\n') 86 if err != nil { 87 if err != io.EOF { 88 log.Fatalf("nextLine: expected EOF, received %v", err) 89 } 90 return s, err 91 } 92 return s[:len(s)-1], nil 93 } 94 95 // processLog verifies whether the given ThreadSanitizer's log 96 // contains a race report, checks this information against 97 // the name of the testcase and returns the result of this 98 // comparison. 99 func processLog(testName string, tsanLog []string) string { 100 if !strings.HasPrefix(testName, "Race") && !strings.HasPrefix(testName, "NoRace") { 101 return "" 102 } 103 gotRace := false 104 for _, s := range tsanLog { 105 if strings.Contains(s, "DATA RACE") { 106 gotRace = true 107 break 108 } 109 } 110 111 failing := strings.Contains(testName, "Failing") 112 expRace := !strings.HasPrefix(testName, "No") 113 for len(testName) < visibleLen { 114 testName += " " 115 } 116 if expRace == gotRace { 117 passedTests++ 118 totalTests++ 119 if failing { 120 failed = true 121 failingNeg++ 122 } 123 return fmt.Sprintf("%s .", testName) 124 } 125 pos := "" 126 if expRace { 127 falseNeg++ 128 } else { 129 falsePos++ 130 pos = "+" 131 } 132 if failing { 133 failingPos++ 134 } else { 135 failed = true 136 } 137 totalTests++ 138 return fmt.Sprintf("%s %s%s", testName, "FAILED", pos) 139 } 140 141 // runTests assures that the package and its dependencies is 142 // built with instrumentation enabled and returns the output of 'go test' 143 // which includes possible data race reports from ThreadSanitizer. 144 func runTests() ([]byte, error) { 145 tests, err := filepath.Glob("./testdata/*_test.go") 146 if err != nil { 147 return nil, err 148 } 149 args := []string{"test", "-race", "-v"} 150 args = append(args, tests...) 151 cmd := exec.Command("go", args...) 152 // The following flags turn off heuristics that suppress seemingly identical reports. 153 // It is required because the tests contain a lot of data races on the same addresses 154 // (the tests are simple and the memory is constantly reused). 155 for _, env := range os.Environ() { 156 if strings.HasPrefix(env, "GOMAXPROCS=") || strings.HasPrefix(env, "GODEBUG=") { 157 continue 158 } 159 cmd.Env = append(cmd.Env, env) 160 } 161 // We set GOMAXPROCS=1 to prevent test flakiness. 162 // There are two sources of flakiness: 163 // 1. Some tests rely on particular execution order. 164 // If the order is different, race does not happen at all. 165 // 2. Ironically, ThreadSanitizer runtime contains a logical race condition 166 // that can lead to false negatives if racy accesses happen literally at the same time. 167 // Tests used to work reliably in the good old days of GOMAXPROCS=1. 168 // So let's set it for now. A more reliable solution is to explicitly annotate tests 169 // with required execution order by means of a special "invisible" synchronization primitive 170 // (that's what is done for C++ ThreadSanitizer tests). This is issue #14119. 171 cmd.Env = append(cmd.Env, 172 "GOMAXPROCS=1", 173 "GORACE=suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0", 174 ) 175 return cmd.CombinedOutput() 176 } 177 178 func TestIssue8102(t *testing.T) { 179 // If this compiles with -race, the test passes. 180 type S struct { 181 x interface{} 182 i int 183 } 184 c := make(chan int) 185 a := [2]*int{} 186 for ; ; c <- *a[S{}.i] { 187 if t != nil { 188 break 189 } 190 } 191 } 192 193 func TestIssue9137(t *testing.T) { 194 a := []string{"a"} 195 i := 0 196 a[i], a[len(a)-1], a = a[len(a)-1], "", a[:len(a)-1] 197 if len(a) != 0 || a[:1][0] != "" { 198 t.Errorf("mangled a: %q %q", a, a[:1]) 199 } 200 } 201 202 func BenchmarkSyncLeak(b *testing.B) { 203 const ( 204 G = 1000 205 S = 1000 206 H = 10 207 ) 208 var wg sync.WaitGroup 209 wg.Add(G) 210 for g := 0; g < G; g++ { 211 go func() { 212 defer wg.Done() 213 hold := make([][]uint32, H) 214 for i := 0; i < b.N; i++ { 215 a := make([]uint32, S) 216 atomic.AddUint32(&a[rand.Intn(len(a))], 1) 217 hold[rand.Intn(len(hold))] = a 218 } 219 _ = hold 220 }() 221 } 222 wg.Wait() 223 }