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