github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/runtime/crash_unix_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 // +build darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 package runtime_test 8 9 import ( 10 "bytes" 11 "internal/testenv" 12 "io/ioutil" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "runtime" 17 "strings" 18 "syscall" 19 "testing" 20 ) 21 22 // sigquit is the signal to send to kill a hanging testdata program. 23 // Send SIGQUIT to get a stack trace. 24 var sigquit = syscall.SIGQUIT 25 26 func TestCrashDumpsAllThreads(t *testing.T) { 27 switch runtime.GOOS { 28 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": 29 default: 30 t.Skipf("skipping; not supported on %v", runtime.GOOS) 31 } 32 33 // We don't use executeTest because we need to kill the 34 // program while it is running. 35 36 testenv.MustHaveGoBuild(t) 37 38 checkStaleRuntime(t) 39 40 t.Parallel() 41 42 dir, err := ioutil.TempDir("", "go-build") 43 if err != nil { 44 t.Fatalf("failed to create temp directory: %v", err) 45 } 46 defer os.RemoveAll(dir) 47 48 if err := ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte(crashDumpsAllThreadsSource), 0666); err != nil { 49 t.Fatalf("failed to create Go file: %v", err) 50 } 51 52 cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe") 53 cmd.Dir = dir 54 out, err := testEnv(cmd).CombinedOutput() 55 if err != nil { 56 t.Fatalf("building source: %v\n%s", err, out) 57 } 58 59 cmd = exec.Command(filepath.Join(dir, "a.exe")) 60 cmd = testEnv(cmd) 61 cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") 62 63 // Set GOGC=off. Because of golang.org/issue/10958, the tight 64 // loops in the test program are not preemptible. If GC kicks 65 // in, it may lock up and prevent main from saying it's ready. 66 newEnv := []string{} 67 for _, s := range cmd.Env { 68 if !strings.HasPrefix(s, "GOGC=") { 69 newEnv = append(newEnv, s) 70 } 71 } 72 cmd.Env = append(newEnv, "GOGC=off") 73 74 var outbuf bytes.Buffer 75 cmd.Stdout = &outbuf 76 cmd.Stderr = &outbuf 77 78 rp, wp, err := os.Pipe() 79 if err != nil { 80 t.Fatal(err) 81 } 82 cmd.ExtraFiles = []*os.File{wp} 83 84 if err := cmd.Start(); err != nil { 85 t.Fatalf("starting program: %v", err) 86 } 87 88 if err := wp.Close(); err != nil { 89 t.Logf("closing write pipe: %v", err) 90 } 91 if _, err := rp.Read(make([]byte, 1)); err != nil { 92 t.Fatalf("reading from pipe: %v", err) 93 } 94 95 if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil { 96 t.Fatalf("signal: %v", err) 97 } 98 99 // No point in checking the error return from Wait--we expect 100 // it to fail. 101 cmd.Wait() 102 103 // We want to see a stack trace for each thread. 104 // Before https://golang.org/cl/2811 running threads would say 105 // "goroutine running on other thread; stack unavailable". 106 out = outbuf.Bytes() 107 n := bytes.Count(out, []byte("main.loop(")) 108 if n != 4 { 109 t.Errorf("found %d instances of main.loop; expected 4", n) 110 t.Logf("%s", out) 111 } 112 } 113 114 const crashDumpsAllThreadsSource = ` 115 package main 116 117 import ( 118 "fmt" 119 "os" 120 "runtime" 121 ) 122 123 func main() { 124 const count = 4 125 runtime.GOMAXPROCS(count + 1) 126 127 chans := make([]chan bool, count) 128 for i := range chans { 129 chans[i] = make(chan bool) 130 go loop(i, chans[i]) 131 } 132 133 // Wait for all the goroutines to start executing. 134 for _, c := range chans { 135 <-c 136 } 137 138 // Tell our parent that all the goroutines are executing. 139 if _, err := os.NewFile(3, "pipe").WriteString("x"); err != nil { 140 fmt.Fprintf(os.Stderr, "write to pipe failed: %v\n", err) 141 os.Exit(2) 142 } 143 144 select {} 145 } 146 147 func loop(i int, c chan bool) { 148 close(c) 149 for { 150 for j := 0; j < 0x7fffffff; j++ { 151 } 152 } 153 } 154 ` 155 156 func TestSignalExitStatus(t *testing.T) { 157 testenv.MustHaveGoBuild(t) 158 exe, err := buildTestProg(t, "testprog") 159 if err != nil { 160 t.Fatal(err) 161 } 162 err = testEnv(exec.Command(exe, "SignalExitStatus")).Run() 163 if err == nil { 164 t.Error("test program succeeded unexpectedly") 165 } else if ee, ok := err.(*exec.ExitError); !ok { 166 t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err) 167 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok { 168 t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys()) 169 } else if !ws.Signaled() || ws.Signal() != syscall.SIGTERM { 170 t.Errorf("got %v; expected SIGTERM", ee) 171 } 172 } 173 174 func TestSignalIgnoreSIGTRAP(t *testing.T) { 175 output := runTestProg(t, "testprognet", "SignalIgnoreSIGTRAP") 176 want := "OK\n" 177 if output != want { 178 t.Fatalf("want %s, got %s\n", want, output) 179 } 180 }