1
2
3
4
5
6
7
8
9
10
11
12 package race_test
13
14 import (
15 "bufio"
16 "bytes"
17 "fmt"
18 "internal/testenv"
19 "io"
20 "log"
21 "math/rand"
22 "os"
23 "os/exec"
24 "path/filepath"
25 "strings"
26 "sync"
27 "sync/atomic"
28 "testing"
29 )
30
31 var (
32 passedTests = 0
33 totalTests = 0
34 falsePos = 0
35 falseNeg = 0
36 failingPos = 0
37 failingNeg = 0
38 failed = false
39 )
40
41 const (
42 visibleLen = 40
43 testPrefix = "=== RUN Test"
44 )
45
46 func TestRace(t *testing.T) {
47 testOutput, err := runTests(t)
48 if err != nil {
49 t.Fatalf("Failed to run tests: %v\n%v", err, string(testOutput))
50 }
51 reader := bufio.NewReader(bytes.NewReader(testOutput))
52
53 funcName := ""
54 var tsanLog []string
55 for {
56 s, err := nextLine(reader)
57 if err != nil {
58 fmt.Printf("%s\n", processLog(funcName, tsanLog))
59 break
60 }
61 if strings.HasPrefix(s, testPrefix) {
62 fmt.Printf("%s\n", processLog(funcName, tsanLog))
63 tsanLog = make([]string, 0, 100)
64 funcName = s[len(testPrefix):]
65 } else {
66 tsanLog = append(tsanLog, s)
67 }
68 }
69
70 if totalTests == 0 {
71 t.Fatalf("failed to parse test output:\n%s", testOutput)
72 }
73 fmt.Printf("\nPassed %d of %d tests (%.02f%%, %d+, %d-)\n",
74 passedTests, totalTests, 100*float64(passedTests)/float64(totalTests), falsePos, falseNeg)
75 fmt.Printf("%d expected failures (%d has not fail)\n", failingPos+failingNeg, failingNeg)
76 if failed {
77 t.Fail()
78 }
79 }
80
81
82
83
84
85 func nextLine(r *bufio.Reader) (string, error) {
86 s, err := r.ReadString('\n')
87 if err != nil {
88 if err != io.EOF {
89 log.Fatalf("nextLine: expected EOF, received %v", err)
90 }
91 return s, err
92 }
93 return s[:len(s)-1], nil
94 }
95
96
97
98
99
100 func processLog(testName string, tsanLog []string) string {
101 if !strings.HasPrefix(testName, "Race") && !strings.HasPrefix(testName, "NoRace") {
102 return ""
103 }
104 gotRace := false
105 for _, s := range tsanLog {
106 if strings.Contains(s, "DATA RACE") {
107 gotRace = true
108 break
109 }
110 if strings.Contains(s, "fatal error: concurrent map") {
111
112 gotRace = true
113 break
114 }
115 }
116
117 failing := strings.Contains(testName, "Failing")
118 expRace := !strings.HasPrefix(testName, "No")
119 for len(testName) < visibleLen {
120 testName += " "
121 }
122 if expRace == gotRace {
123 passedTests++
124 totalTests++
125 if failing {
126 failed = true
127 failingNeg++
128 }
129 return fmt.Sprintf("%s .", testName)
130 }
131 pos := ""
132 if expRace {
133 falseNeg++
134 } else {
135 falsePos++
136 pos = "+"
137 }
138 if failing {
139 failingPos++
140 } else {
141 failed = true
142 }
143 totalTests++
144 return fmt.Sprintf("%s %s%s", testName, "FAILED", pos)
145 }
146
147
148
149
150 func runTests(t *testing.T) ([]byte, error) {
151 tests, err := filepath.Glob("./testdata/*_test.go")
152 if err != nil {
153 return nil, err
154 }
155 args := []string{"test", "-race", "-v"}
156 args = append(args, tests...)
157 cmd := exec.Command(testenv.GoToolPath(t), args...)
158
159
160
161 for _, env := range os.Environ() {
162 if strings.HasPrefix(env, "GOMAXPROCS=") ||
163 strings.HasPrefix(env, "GODEBUG=") ||
164 strings.HasPrefix(env, "GORACE=") {
165 continue
166 }
167 cmd.Env = append(cmd.Env, env)
168 }
169
170
171
172
173
174
175
176
177
178
179 cmd.Env = append(cmd.Env,
180 "GOMAXPROCS=1",
181 "GORACE=suppress_equal_stacks=0 suppress_equal_addresses=0",
182 )
183
184 out, _ := cmd.CombinedOutput()
185 fatals := bytes.Count(out, []byte("fatal error:"))
186 mapFatals := bytes.Count(out, []byte("fatal error: concurrent map"))
187 if fatals > mapFatals {
188
189
190 return out, fmt.Errorf("runtime fatal error")
191 }
192 return out, nil
193 }
194
195 func TestIssue8102(t *testing.T) {
196
197 type S struct {
198 x any
199 i int
200 }
201 c := make(chan int)
202 a := [2]*int{}
203 for ; ; c <- *a[S{}.i] {
204 if t != nil {
205 break
206 }
207 }
208 }
209
210 func TestIssue9137(t *testing.T) {
211 a := []string{"a"}
212 i := 0
213 a[i], a[len(a)-1], a = a[len(a)-1], "", a[:len(a)-1]
214 if len(a) != 0 || a[:1][0] != "" {
215 t.Errorf("mangled a: %q %q", a, a[:1])
216 }
217 }
218
219 func BenchmarkSyncLeak(b *testing.B) {
220 const (
221 G = 1000
222 S = 1000
223 H = 10
224 )
225 var wg sync.WaitGroup
226 wg.Add(G)
227 for g := 0; g < G; g++ {
228 go func() {
229 defer wg.Done()
230 hold := make([][]uint32, H)
231 for i := 0; i < b.N; i++ {
232 a := make([]uint32, S)
233 atomic.AddUint32(&a[rand.Intn(len(a))], 1)
234 hold[rand.Intn(len(hold))] = a
235 }
236 _ = hold
237 }()
238 }
239 wg.Wait()
240 }
241
242 func BenchmarkStackLeak(b *testing.B) {
243 done := make(chan bool, 1)
244 for i := 0; i < b.N; i++ {
245 go func() {
246 growStack(rand.Intn(100))
247 done <- true
248 }()
249 <-done
250 }
251 }
252
253 func growStack(i int) {
254 if i == 0 {
255 return
256 }
257 growStack(i - 1)
258 }
259
View as plain text