runtime: Remove now unnecessary pad field from ParFor.
[gcc.git] / libgo / go / runtime / crash_test.go
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 package runtime_test
6
7 import (
8 "fmt"
9 "internal/testenv"
10 "io/ioutil"
11 "os"
12 "os/exec"
13 "path/filepath"
14 "regexp"
15 "runtime"
16 "strings"
17 "sync"
18 "testing"
19 "text/template"
20 )
21
22 func testEnv(cmd *exec.Cmd) *exec.Cmd {
23 if cmd.Env != nil {
24 panic("environment already set")
25 }
26 for _, env := range os.Environ() {
27 // Exclude GODEBUG from the environment to prevent its output
28 // from breaking tests that are trying to parse other command output.
29 if strings.HasPrefix(env, "GODEBUG=") {
30 continue
31 }
32 // Exclude GOTRACEBACK for the same reason.
33 if strings.HasPrefix(env, "GOTRACEBACK=") {
34 continue
35 }
36 cmd.Env = append(cmd.Env, env)
37 }
38 return cmd
39 }
40
41 func executeTest(t *testing.T, templ string, data interface{}, extra ...string) string {
42 testenv.MustHaveGoBuild(t)
43
44 checkStaleRuntime(t)
45
46 st := template.Must(template.New("crashSource").Parse(templ))
47
48 dir, err := ioutil.TempDir("", "go-build")
49 if err != nil {
50 t.Fatalf("failed to create temp directory: %v", err)
51 }
52 defer os.RemoveAll(dir)
53
54 src := filepath.Join(dir, "main.go")
55 f, err := os.Create(src)
56 if err != nil {
57 t.Fatalf("failed to create file: %v", err)
58 }
59 err = st.Execute(f, data)
60 if err != nil {
61 f.Close()
62 t.Fatalf("failed to execute template: %v", err)
63 }
64 if err := f.Close(); err != nil {
65 t.Fatalf("failed to close file: %v", err)
66 }
67
68 for i := 0; i < len(extra); i += 2 {
69 fname := extra[i]
70 contents := extra[i+1]
71 if d, _ := filepath.Split(fname); d != "" {
72 if err := os.Mkdir(filepath.Join(dir, d), 0755); err != nil {
73 t.Fatal(err)
74 }
75 }
76 if err := ioutil.WriteFile(filepath.Join(dir, fname), []byte(contents), 0666); err != nil {
77 t.Fatal(err)
78 }
79 }
80
81 cmd := exec.Command("go", "build", "-o", "a.exe")
82 cmd.Dir = dir
83 out, err := testEnv(cmd).CombinedOutput()
84 if err != nil {
85 t.Fatalf("building source: %v\n%s", err, out)
86 }
87
88 got, _ := testEnv(exec.Command(filepath.Join(dir, "a.exe"))).CombinedOutput()
89 return string(got)
90 }
91
92 var (
93 staleRuntimeOnce sync.Once // guards init of staleRuntimeErr
94 staleRuntimeErr error
95 )
96
97 func checkStaleRuntime(t *testing.T) {
98 staleRuntimeOnce.Do(func() {
99 // 'go run' uses the installed copy of runtime.a, which may be out of date.
100 out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
101 if err != nil {
102 staleRuntimeErr = fmt.Errorf("failed to execute 'go list': %v\n%v", err, string(out))
103 return
104 }
105 if string(out) != "false\n" {
106 staleRuntimeErr = fmt.Errorf("Stale runtime.a. Run 'go install runtime'.")
107 }
108 })
109 if staleRuntimeErr != nil {
110 t.Fatal(staleRuntimeErr)
111 }
112 }
113
114 func testCrashHandler(t *testing.T, cgo bool) {
115 type crashTest struct {
116 Cgo bool
117 }
118 output := executeTest(t, crashSource, &crashTest{Cgo: cgo})
119 want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
120 if output != want {
121 t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
122 }
123 }
124
125 func TestCrashHandler(t *testing.T) {
126 testCrashHandler(t, false)
127 }
128
129 func testDeadlock(t *testing.T, source string) {
130 output := executeTest(t, source, nil)
131 want := "fatal error: all goroutines are asleep - deadlock!\n"
132 if !strings.HasPrefix(output, want) {
133 t.Fatalf("output does not start with %q:\n%s", want, output)
134 }
135 }
136
137 func TestSimpleDeadlock(t *testing.T) {
138 testDeadlock(t, simpleDeadlockSource)
139 }
140
141 func TestInitDeadlock(t *testing.T) {
142 testDeadlock(t, initDeadlockSource)
143 }
144
145 func TestLockedDeadlock(t *testing.T) {
146 testDeadlock(t, lockedDeadlockSource)
147 }
148
149 func TestLockedDeadlock2(t *testing.T) {
150 testDeadlock(t, lockedDeadlockSource2)
151 }
152
153 func TestGoexitDeadlock(t *testing.T) {
154 output := executeTest(t, goexitDeadlockSource, nil)
155 want := "no goroutines (main called runtime.Goexit) - deadlock!"
156 if !strings.Contains(output, want) {
157 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
158 }
159 }
160
161 func TestStackOverflow(t *testing.T) {
162 output := executeTest(t, stackOverflowSource, nil)
163 want := "runtime: goroutine stack exceeds 4194304-byte limit\nfatal error: stack overflow"
164 if !strings.HasPrefix(output, want) {
165 t.Fatalf("output does not start with %q:\n%s", want, output)
166 }
167 }
168
169 func TestThreadExhaustion(t *testing.T) {
170 output := executeTest(t, threadExhaustionSource, nil)
171 want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
172 if !strings.HasPrefix(output, want) {
173 t.Fatalf("output does not start with %q:\n%s", want, output)
174 }
175 }
176
177 func TestRecursivePanic(t *testing.T) {
178 output := executeTest(t, recursivePanicSource, nil)
179 want := `wrap: bad
180 panic: again
181
182 `
183 if !strings.HasPrefix(output, want) {
184 t.Fatalf("output does not start with %q:\n%s", want, output)
185 }
186
187 }
188
189 func TestGoexitCrash(t *testing.T) {
190 output := executeTest(t, goexitExitSource, nil)
191 want := "no goroutines (main called runtime.Goexit) - deadlock!"
192 if !strings.Contains(output, want) {
193 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
194 }
195 }
196
197 func TestGoexitDefer(t *testing.T) {
198 c := make(chan struct{})
199 go func() {
200 defer func() {
201 r := recover()
202 if r != nil {
203 t.Errorf("non-nil recover during Goexit")
204 }
205 c <- struct{}{}
206 }()
207 runtime.Goexit()
208 }()
209 // Note: if the defer fails to run, we will get a deadlock here
210 <-c
211 }
212
213 func TestGoNil(t *testing.T) {
214 output := executeTest(t, goNilSource, nil)
215 want := "go of nil func value"
216 if !strings.Contains(output, want) {
217 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
218 }
219 }
220
221 func TestMainGoroutineId(t *testing.T) {
222 output := executeTest(t, mainGoroutineIdSource, nil)
223 want := "panic: test\n\ngoroutine 1 [running]:\n"
224 if !strings.HasPrefix(output, want) {
225 t.Fatalf("output does not start with %q:\n%s", want, output)
226 }
227 }
228
229 func TestNoHelperGoroutines(t *testing.T) {
230 output := executeTest(t, noHelperGoroutinesSource, nil)
231 matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1)
232 if len(matches) != 1 || matches[0][0] != "goroutine 1 [" {
233 t.Fatalf("want to see only goroutine 1, see:\n%s", output)
234 }
235 }
236
237 func TestBreakpoint(t *testing.T) {
238 output := executeTest(t, breakpointSource, nil)
239 want := "runtime.Breakpoint()"
240 if !strings.Contains(output, want) {
241 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
242 }
243 }
244
245 const crashSource = `
246 package main
247
248 import (
249 "fmt"
250 "runtime"
251 )
252
253 {{if .Cgo}}
254 import "C"
255 {{end}}
256
257 func test(name string) {
258 defer func() {
259 if x := recover(); x != nil {
260 fmt.Printf(" recovered")
261 }
262 fmt.Printf(" done\n")
263 }()
264 fmt.Printf("%s:", name)
265 var s *string
266 _ = *s
267 fmt.Print("SHOULD NOT BE HERE")
268 }
269
270 func testInNewThread(name string) {
271 c := make(chan bool)
272 go func() {
273 runtime.LockOSThread()
274 test(name)
275 c <- true
276 }()
277 <-c
278 }
279
280 func main() {
281 runtime.LockOSThread()
282 test("main")
283 testInNewThread("new-thread")
284 testInNewThread("second-new-thread")
285 test("main-again")
286 }
287 `
288
289 const simpleDeadlockSource = `
290 package main
291 func main() {
292 select {}
293 }
294 `
295
296 const initDeadlockSource = `
297 package main
298 func init() {
299 select {}
300 }
301 func main() {
302 }
303 `
304
305 const lockedDeadlockSource = `
306 package main
307 import "runtime"
308 func main() {
309 runtime.LockOSThread()
310 select {}
311 }
312 `
313
314 const lockedDeadlockSource2 = `
315 package main
316 import (
317 "runtime"
318 "time"
319 )
320 func main() {
321 go func() {
322 runtime.LockOSThread()
323 select {}
324 }()
325 time.Sleep(time.Millisecond)
326 select {}
327 }
328 `
329
330 const goexitDeadlockSource = `
331 package main
332 import (
333 "runtime"
334 )
335
336 func F() {
337 for i := 0; i < 10; i++ {
338 }
339 }
340
341 func main() {
342 go F()
343 go F()
344 runtime.Goexit()
345 }
346 `
347
348 const stackOverflowSource = `
349 package main
350
351 import "runtime/debug"
352
353 func main() {
354 debug.SetMaxStack(4<<20)
355 f(make([]byte, 10))
356 }
357
358 func f(x []byte) byte {
359 var buf [64<<10]byte
360 return x[0] + f(buf[:])
361 }
362 `
363
364 const threadExhaustionSource = `
365 package main
366
367 import (
368 "runtime"
369 "runtime/debug"
370 )
371
372 func main() {
373 debug.SetMaxThreads(10)
374 c := make(chan int)
375 for i := 0; i < 100; i++ {
376 go func() {
377 runtime.LockOSThread()
378 c <- 0
379 select{}
380 }()
381 <-c
382 }
383 }
384 `
385
386 const recursivePanicSource = `
387 package main
388
389 import (
390 "fmt"
391 )
392
393 func main() {
394 func() {
395 defer func() {
396 fmt.Println(recover())
397 }()
398 var x [8192]byte
399 func(x [8192]byte) {
400 defer func() {
401 if err := recover(); err != nil {
402 panic("wrap: " + err.(string))
403 }
404 }()
405 panic("bad")
406 }(x)
407 }()
408 panic("again")
409 }
410 `
411
412 const goexitExitSource = `
413 package main
414
415 import (
416 "runtime"
417 "time"
418 )
419
420 func main() {
421 go func() {
422 time.Sleep(time.Millisecond)
423 }()
424 i := 0
425 runtime.SetFinalizer(&i, func(p *int) {})
426 runtime.GC()
427 runtime.Goexit()
428 }
429 `
430
431 const goNilSource = `
432 package main
433
434 func main() {
435 defer func() {
436 recover()
437 }()
438 var f func()
439 go f()
440 select{}
441 }
442 `
443
444 const mainGoroutineIdSource = `
445 package main
446 func main() {
447 panic("test")
448 }
449 `
450
451 const noHelperGoroutinesSource = `
452 package main
453 import (
454 "runtime"
455 "time"
456 )
457 func init() {
458 i := 0
459 runtime.SetFinalizer(&i, func(p *int) {})
460 time.AfterFunc(time.Hour, func() {})
461 panic("oops")
462 }
463 func main() {
464 }
465 `
466
467 const breakpointSource = `
468 package main
469 import "runtime"
470 func main() {
471 runtime.Breakpoint()
472 }
473 `
474
475 func TestGoexitInPanic(t *testing.T) {
476 // see issue 8774: this code used to trigger an infinite recursion
477 output := executeTest(t, goexitInPanicSource, nil)
478 want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
479 if !strings.HasPrefix(output, want) {
480 t.Fatalf("output does not start with %q:\n%s", want, output)
481 }
482 }
483
484 const goexitInPanicSource = `
485 package main
486 import "runtime"
487 func main() {
488 go func() {
489 defer func() {
490 runtime.Goexit()
491 }()
492 panic("hello")
493 }()
494 runtime.Goexit()
495 }
496 `
497
498 func TestPanicAfterGoexit(t *testing.T) {
499 // an uncaught panic should still work after goexit
500 output := executeTest(t, panicAfterGoexitSource, nil)
501 want := "panic: hello"
502 if !strings.HasPrefix(output, want) {
503 t.Fatalf("output does not start with %q:\n%s", want, output)
504 }
505 }
506
507 const panicAfterGoexitSource = `
508 package main
509 import "runtime"
510 func main() {
511 defer func() {
512 panic("hello")
513 }()
514 runtime.Goexit()
515 }
516 `
517
518 func TestRecoveredPanicAfterGoexit(t *testing.T) {
519 output := executeTest(t, recoveredPanicAfterGoexitSource, nil)
520 want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
521 if !strings.HasPrefix(output, want) {
522 t.Fatalf("output does not start with %q:\n%s", want, output)
523 }
524 }
525
526 const recoveredPanicAfterGoexitSource = `
527 package main
528 import "runtime"
529 func main() {
530 defer func() {
531 defer func() {
532 r := recover()
533 if r == nil {
534 panic("bad recover")
535 }
536 }()
537 panic("hello")
538 }()
539 runtime.Goexit()
540 }
541 `
542
543 func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
544 // 1. defer a function that recovers
545 // 2. defer a function that panics
546 // 3. call goexit
547 // Goexit should run the #2 defer. Its panic
548 // should be caught by the #1 defer, and execution
549 // should resume in the caller. Like the Goexit
550 // never happened!
551 defer func() {
552 r := recover()
553 if r == nil {
554 panic("bad recover")
555 }
556 }()
557 defer func() {
558 panic("hello")
559 }()
560 runtime.Goexit()
561 }
562
563 func TestNetpollDeadlock(t *testing.T) {
564 output := executeTest(t, netpollDeadlockSource, nil)
565 want := "done\n"
566 if !strings.HasSuffix(output, want) {
567 t.Fatalf("output does not start with %q:\n%s", want, output)
568 }
569 }
570
571 const netpollDeadlockSource = `
572 package main
573 import (
574 "fmt"
575 "net"
576 )
577 func init() {
578 fmt.Println("dialing")
579 c, err := net.Dial("tcp", "localhost:14356")
580 if err == nil {
581 c.Close()
582 } else {
583 fmt.Println("error: ", err)
584 }
585 }
586 func main() {
587 fmt.Println("done")
588 }
589 `