1
2
3
4
5
6
7
8
9
10
11
12
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
83
84
85
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
98
99
100
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
144
145
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
155
156
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
166
167
168
169
170
171
172
173
174
175 cmd.Env = append(cmd.Env,
176 "GOMAXPROCS=1",
177 "GORACE=suppress_equal_stacks=0 suppress_equal_addresses=0",
178 )
179
180 out, _ := cmd.CombinedOutput()
181 if bytes.Contains(out, []byte("fatal error:")) {
182
183 return out, fmt.Errorf("runtime fatal error")
184 }
185 return out, nil
186 }
187
188 func TestIssue8102(t *testing.T) {
189
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 }
252
View as plain text