blob: 85fcc69fedca65bbc6677ed311276a2939f7afca [file] [log] [blame]
Alex Brainmanafe0e972012-05-30 15:10:54 +10001// 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
5package runtime_test
6
7import (
Brad Fitzpatrickb70ddc02015-01-05 13:14:08 -08008 "fmt"
Russ Cox7bc3e582015-06-05 11:01:53 -04009 "internal/testenv"
Alex Brainmanafe0e972012-05-30 15:10:54 +100010 "io/ioutil"
11 "os"
12 "os/exec"
13 "path/filepath"
Dmitry Vyukov59495e82015-02-07 15:31:18 +030014 "regexp"
Russ Cox0c2a7272014-05-20 12:10:19 -040015 "runtime"
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +040016 "strings"
Brad Fitzpatrickb70ddc02015-01-05 13:14:08 -080017 "sync"
Alex Brainmanafe0e972012-05-30 15:10:54 +100018 "testing"
Alex Brainmanafe0e972012-05-30 15:10:54 +100019)
20
Russ Cox8d5ff2e2015-12-21 10:29:21 -050021var toRemove []string
22
23func TestMain(m *testing.M) {
24 status := m.Run()
25 for _, file := range toRemove {
26 os.RemoveAll(file)
27 }
28 os.Exit(status)
29}
30
Albert Strasheim4235fa82013-04-07 11:37:37 -070031func testEnv(cmd *exec.Cmd) *exec.Cmd {
32 if cmd.Env != nil {
33 panic("environment already set")
34 }
35 for _, env := range os.Environ() {
Dmitry Vyukov59495e82015-02-07 15:31:18 +030036 // Exclude GODEBUG from the environment to prevent its output
37 // from breaking tests that are trying to parse other command output.
Dmitriy Vyukov4b536a52013-06-28 18:37:06 +040038 if strings.HasPrefix(env, "GODEBUG=") {
Albert Strasheim4235fa82013-04-07 11:37:37 -070039 continue
40 }
Dmitry Vyukov59495e82015-02-07 15:31:18 +030041 // Exclude GOTRACEBACK for the same reason.
42 if strings.HasPrefix(env, "GOTRACEBACK=") {
43 continue
44 }
Albert Strasheim4235fa82013-04-07 11:37:37 -070045 cmd.Env = append(cmd.Env, env)
46 }
47 return cmd
48}
49
Russ Cox8d5ff2e2015-12-21 10:29:21 -050050var testprog struct {
51 sync.Mutex
52 dir string
53 target map[string]buildexe
54}
55
56type buildexe struct {
57 exe string
58 err error
59}
60
61func runTestProg(t *testing.T, binary, name string) string {
Russ Cox7bc3e582015-06-05 11:01:53 -040062 testenv.MustHaveGoBuild(t)
Russ Cox0c2a7272014-05-20 12:10:19 -040063
Russ Cox8d5ff2e2015-12-21 10:29:21 -050064 exe, err := buildTestProg(t, binary)
65 if err != nil {
66 t.Fatal(err)
67 }
68 got, _ := testEnv(exec.Command(exe, name)).CombinedOutput()
69 return string(got)
70}
71
72func buildTestProg(t *testing.T, binary string) (string, error) {
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +040073 checkStaleRuntime(t)
Alex Brainmanafe0e972012-05-30 15:10:54 +100074
Russ Cox8d5ff2e2015-12-21 10:29:21 -050075 testprog.Lock()
76 defer testprog.Unlock()
77 if testprog.dir == "" {
78 dir, err := ioutil.TempDir("", "go-build")
79 if err != nil {
80 t.Fatalf("failed to create temp directory: %v", err)
Alex Brainman9b691962015-03-16 15:46:22 +110081 }
Russ Cox8d5ff2e2015-12-21 10:29:21 -050082 testprog.dir = dir
83 toRemove = append(toRemove, dir)
Russ Coxc4efaac2014-10-28 21:53:09 -040084 }
85
Russ Cox8d5ff2e2015-12-21 10:29:21 -050086 if testprog.target == nil {
87 testprog.target = make(map[string]buildexe)
88 }
89 target, ok := testprog.target[binary]
90 if ok {
91 return target.exe, target.err
92 }
93
94 exe := filepath.Join(testprog.dir, binary+".exe")
95 cmd := exec.Command("go", "build", "-o", exe)
96 cmd.Dir = "testdata/" + binary
Russ Coxc4efaac2014-10-28 21:53:09 -040097 out, err := testEnv(cmd).CombinedOutput()
98 if err != nil {
Russ Cox8d5ff2e2015-12-21 10:29:21 -050099 exe = ""
100 target.err = fmt.Errorf("building %s: %v\n%s", binary, err, out)
101 testprog.target[binary] = target
Ian Lance Taylore13a0822016-01-11 09:34:38 -0800102 return "", target.err
Russ Coxc4efaac2014-10-28 21:53:09 -0400103 }
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500104 target.exe = exe
105 testprog.target[binary] = target
106 return exe, nil
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +0400107}
108
Brad Fitzpatrickb70ddc02015-01-05 13:14:08 -0800109var (
110 staleRuntimeOnce sync.Once // guards init of staleRuntimeErr
111 staleRuntimeErr error
112)
113
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +0400114func checkStaleRuntime(t *testing.T) {
Brad Fitzpatrickb70ddc02015-01-05 13:14:08 -0800115 staleRuntimeOnce.Do(func() {
116 // 'go run' uses the installed copy of runtime.a, which may be out of date.
117 out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
118 if err != nil {
119 staleRuntimeErr = fmt.Errorf("failed to execute 'go list': %v\n%v", err, string(out))
120 return
121 }
122 if string(out) != "false\n" {
123 staleRuntimeErr = fmt.Errorf("Stale runtime.a. Run 'go install runtime'.")
124 }
125 })
126 if staleRuntimeErr != nil {
127 t.Fatal(staleRuntimeErr)
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +0400128 }
129}
130
131func testCrashHandler(t *testing.T, cgo bool) {
132 type crashTest struct {
133 Cgo bool
134 }
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500135 var output string
136 if cgo {
137 output = runTestProg(t, "testprogcgo", "Crash")
138 } else {
139 output = runTestProg(t, "testprog", "Crash")
140 }
Alex Brainmanafe0e972012-05-30 15:10:54 +1000141 want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
Russ Cox757e0de2013-08-15 22:34:06 -0400142 if output != want {
143 t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
Alex Brainmanafe0e972012-05-30 15:10:54 +1000144 }
145}
146
147func TestCrashHandler(t *testing.T) {
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +0400148 testCrashHandler(t, false)
149}
150
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500151func testDeadlock(t *testing.T, name string) {
152 output := runTestProg(t, "testprog", name)
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +0400153 want := "fatal error: all goroutines are asleep - deadlock!\n"
Russ Cox757e0de2013-08-15 22:34:06 -0400154 if !strings.HasPrefix(output, want) {
155 t.Fatalf("output does not start with %q:\n%s", want, output)
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +0400156 }
157}
158
159func TestSimpleDeadlock(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500160 testDeadlock(t, "SimpleDeadlock")
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +0400161}
162
163func TestInitDeadlock(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500164 testDeadlock(t, "InitDeadlock")
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +0400165}
166
167func TestLockedDeadlock(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500168 testDeadlock(t, "LockedDeadlock")
Dmitriy Vyukov06a488f2013-02-20 12:15:02 +0400169}
170
171func TestLockedDeadlock2(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500172 testDeadlock(t, "LockedDeadlock2")
Alex Brainmanafe0e972012-05-30 15:10:54 +1000173}
174
Dmitriy Vyukov2fe840f2013-03-05 09:40:17 +0200175func TestGoexitDeadlock(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500176 output := runTestProg(t, "testprog", "GoexitDeadlock")
Russ Coxade6bc62014-04-16 13:12:18 -0400177 want := "no goroutines (main called runtime.Goexit) - deadlock!"
178 if !strings.Contains(output, want) {
179 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
Russ Cox757e0de2013-08-15 22:34:06 -0400180 }
181}
182
183func TestStackOverflow(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500184 output := runTestProg(t, "testprog", "StackOverflow")
185 want := "runtime: goroutine stack exceeds 1474560-byte limit\nfatal error: stack overflow"
Russ Cox757e0de2013-08-15 22:34:06 -0400186 if !strings.HasPrefix(output, want) {
187 t.Fatalf("output does not start with %q:\n%s", want, output)
Dmitriy Vyukov2fe840f2013-03-05 09:40:17 +0200188 }
189}
190
Russ Cox665feee2013-08-16 22:25:26 -0400191func TestThreadExhaustion(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500192 output := runTestProg(t, "testprog", "ThreadExhaustion")
Russ Cox665feee2013-08-16 22:25:26 -0400193 want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
194 if !strings.HasPrefix(output, want) {
195 t.Fatalf("output does not start with %q:\n%s", want, output)
196 }
197}
198
Dmitriy Vyukovf946a7c2014-03-07 20:50:30 +0400199func TestRecursivePanic(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500200 output := runTestProg(t, "testprog", "RecursivePanic")
Dmitriy Vyukovf946a7c2014-03-07 20:50:30 +0400201 want := `wrap: bad
202panic: again
203
204`
205 if !strings.HasPrefix(output, want) {
206 t.Fatalf("output does not start with %q:\n%s", want, output)
207 }
208
209}
210
Russ Coxade6bc62014-04-16 13:12:18 -0400211func TestGoexitCrash(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500212 output := runTestProg(t, "testprog", "GoexitExit")
Russ Coxade6bc62014-04-16 13:12:18 -0400213 want := "no goroutines (main called runtime.Goexit) - deadlock!"
214 if !strings.Contains(output, want) {
215 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
Dmitriy Vyukov55e0f362014-04-15 19:48:17 +0400216 }
Dmitriy Vyukov55e0f362014-04-15 19:48:17 +0400217}
218
Keith Randall7e623162014-09-15 15:09:17 -0700219func TestGoexitDefer(t *testing.T) {
220 c := make(chan struct{})
221 go func() {
222 defer func() {
223 r := recover()
224 if r != nil {
225 t.Errorf("non-nil recover during Goexit")
226 }
227 c <- struct{}{}
228 }()
229 runtime.Goexit()
230 }()
231 // Note: if the defer fails to run, we will get a deadlock here
232 <-c
233}
234
Dmitriy Vyukovb5caa022014-05-28 00:00:01 -0400235func TestGoNil(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500236 output := runTestProg(t, "testprog", "GoNil")
Dmitriy Vyukovb5caa022014-05-28 00:00:01 -0400237 want := "go of nil func value"
238 if !strings.Contains(output, want) {
239 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
240 }
241}
242
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500243func TestMainGoroutineID(t *testing.T) {
244 output := runTestProg(t, "testprog", "MainGoroutineID")
Dmitriy Vyukovaa763772014-07-16 12:19:33 +0400245 want := "panic: test\n\ngoroutine 1 [running]:\n"
246 if !strings.HasPrefix(output, want) {
247 t.Fatalf("output does not start with %q:\n%s", want, output)
248 }
249}
250
Dmitry Vyukov59495e82015-02-07 15:31:18 +0300251func TestNoHelperGoroutines(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500252 output := runTestProg(t, "testprog", "NoHelperGoroutines")
Dmitry Vyukov59495e82015-02-07 15:31:18 +0300253 matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1)
254 if len(matches) != 1 || matches[0][0] != "goroutine 1 [" {
255 t.Fatalf("want to see only goroutine 1, see:\n%s", output)
256 }
257}
258
Russ Cox1d550b82014-09-11 12:08:30 -0400259func TestBreakpoint(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500260 output := runTestProg(t, "testprog", "Breakpoint")
Russ Cox1d550b82014-09-11 12:08:30 -0400261 want := "runtime.Breakpoint()"
262 if !strings.Contains(output, want) {
263 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
264 }
265}
266
Keith Randall03064782014-09-19 16:33:14 -0700267func TestGoexitInPanic(t *testing.T) {
268 // see issue 8774: this code used to trigger an infinite recursion
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500269 output := runTestProg(t, "testprog", "GoexitInPanic")
Keith Randall03064782014-09-19 16:33:14 -0700270 want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
271 if !strings.HasPrefix(output, want) {
272 t.Fatalf("output does not start with %q:\n%s", want, output)
273 }
274}
275
Keith Randall03064782014-09-19 16:33:14 -0700276func TestPanicAfterGoexit(t *testing.T) {
277 // an uncaught panic should still work after goexit
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500278 output := runTestProg(t, "testprog", "PanicAfterGoexit")
Keith Randall03064782014-09-19 16:33:14 -0700279 want := "panic: hello"
280 if !strings.HasPrefix(output, want) {
281 t.Fatalf("output does not start with %q:\n%s", want, output)
282 }
283}
284
Keith Randall03064782014-09-19 16:33:14 -0700285func TestRecoveredPanicAfterGoexit(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500286 output := runTestProg(t, "testprog", "RecoveredPanicAfterGoexit")
Keith Randall03064782014-09-19 16:33:14 -0700287 want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
288 if !strings.HasPrefix(output, want) {
289 t.Fatalf("output does not start with %q:\n%s", want, output)
290 }
291}
292
Keith Randall03064782014-09-19 16:33:14 -0700293func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
294 // 1. defer a function that recovers
295 // 2. defer a function that panics
296 // 3. call goexit
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000297 // Goexit should run the #2 defer. Its panic
Keith Randall03064782014-09-19 16:33:14 -0700298 // should be caught by the #1 defer, and execution
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000299 // should resume in the caller. Like the Goexit
Keith Randall03064782014-09-19 16:33:14 -0700300 // never happened!
301 defer func() {
302 r := recover()
303 if r == nil {
304 panic("bad recover")
305 }
306 }()
307 defer func() {
308 panic("hello")
309 }()
310 runtime.Goexit()
311}
Dmitry Vyukov776aeca2015-01-13 20:12:50 +0300312
313func TestNetpollDeadlock(t *testing.T) {
Russ Cox8d5ff2e2015-12-21 10:29:21 -0500314 output := runTestProg(t, "testprognet", "NetpollDeadlock")
Dmitry Vyukov776aeca2015-01-13 20:12:50 +0300315 want := "done\n"
316 if !strings.HasSuffix(output, want) {
317 t.Fatalf("output does not start with %q:\n%s", want, output)
318 }
319}
Austin Clements0c02bc02016-02-12 10:33:51 -0500320
321func TestPanicTraceback(t *testing.T) {
322 output := runTestProg(t, "testprog", "PanicTraceback")
323 want := "panic: hello"
324 if !strings.HasPrefix(output, want) {
325 t.Fatalf("output does not start with %q:\n%s", want, output)
326 }
327
328 // Check functions in the traceback.
329 fns := []string{"panic", "main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
330 for _, fn := range fns {
331 re := regexp.MustCompile(`(?m)^` + regexp.QuoteMeta(fn) + `\(.*\n`)
332 idx := re.FindStringIndex(output)
333 if idx == nil {
334 t.Fatalf("expected %q function in traceback:\n%s", fn, output)
335 }
336 output = output[idx[1]:]
337 }
338}
Shenghou Mae9603022016-02-21 13:56:08 -0500339
340func testPanicDeadlock(t *testing.T, name string, want string) {
341 // test issue 14432
342 output := runTestProg(t, "testprog", name)
343 if !strings.HasPrefix(output, want) {
344 t.Fatalf("output does not start with %q:\n%s", want, output)
345 }
346}
347
348func TestPanicDeadlockGosched(t *testing.T) {
349 testPanicDeadlock(t, "GoschedInPanic", "panic: errorThatGosched\n\n")
350}
351
352func TestPanicDeadlockSyscall(t *testing.T) {
353 testPanicDeadlock(t, "SyscallInPanic", "1\n2\npanic: 3\n\n")
354}