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.
5 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
23 // sigquit is the signal to send to kill a hanging testdata program.
24 // Send SIGQUIT to get a stack trace.
25 var sigquit
= syscall
.SIGQUIT
28 if runtime
.Sigisblocked(int(syscall
.SIGQUIT
)) {
29 // We can't use SIGQUIT to kill subprocesses because
30 // it's blocked. Use SIGKILL instead. See issue
31 // #19196 for an example of when this happens.
32 sigquit
= syscall
.SIGKILL
36 func TestCrashDumpsAllThreads(t
*testing
.T
) {
38 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
40 t
.Skipf("skipping; not supported on %v", runtime
.GOOS
)
43 if runtime
.Sigisblocked(int(syscall
.SIGQUIT
)) {
44 t
.Skip("skipping; SIGQUIT is blocked, see golang.org/issue/19196")
47 // We don't use executeTest because we need to kill the
48 // program while it is running.
50 testenv
.MustHaveGoBuild(t
)
56 dir
, err
:= ioutil
.TempDir("", "go-build")
58 t
.Fatalf("failed to create temp directory: %v", err
)
60 defer os
.RemoveAll(dir
)
62 if err
:= ioutil
.WriteFile(filepath
.Join(dir
, "main.go"), []byte(crashDumpsAllThreadsSource
), 0666); err
!= nil {
63 t
.Fatalf("failed to create Go file: %v", err
)
66 cmd
:= exec
.Command(testenv
.GoToolPath(t
), "build", "-o", "a.exe")
68 out
, err
:= testenv
.CleanCmdEnv(cmd
).CombinedOutput()
70 t
.Fatalf("building source: %v\n%s", err
, out
)
73 cmd
= exec
.Command(filepath
.Join(dir
, "a.exe"))
74 cmd
= testenv
.CleanCmdEnv(cmd
)
75 cmd
.Env
= append(cmd
.Env
, "GOTRACEBACK=crash")
77 // Set GOGC=off. Because of golang.org/issue/10958, the tight
78 // loops in the test program are not preemptible. If GC kicks
79 // in, it may lock up and prevent main from saying it's ready.
81 for _
, s
:= range cmd
.Env
{
82 if !strings
.HasPrefix(s
, "GOGC=") {
83 newEnv
= append(newEnv
, s
)
86 cmd
.Env
= append(newEnv
, "GOGC=off")
88 var outbuf bytes
.Buffer
92 rp
, wp
, err
:= os
.Pipe()
96 cmd
.ExtraFiles
= []*os
.File
{wp
}
98 if err
:= cmd
.Start(); err
!= nil {
99 t
.Fatalf("starting program: %v", err
)
102 if err
:= wp
.Close(); err
!= nil {
103 t
.Logf("closing write pipe: %v", err
)
105 if _
, err
:= rp
.Read(make([]byte, 1)); err
!= nil {
106 t
.Fatalf("reading from pipe: %v", err
)
109 if err
:= cmd
.Process
.Signal(syscall
.SIGQUIT
); err
!= nil {
110 t
.Fatalf("signal: %v", err
)
113 // No point in checking the error return from Wait--we expect
117 // We want to see a stack trace for each thread.
118 // Before https://golang.org/cl/2811 running threads would say
119 // "goroutine running on other thread; stack unavailable".
121 n
:= bytes
.Count(out
, []byte("main.loop"))
123 t
.Errorf("found %d instances of main.loop; expected 4", n
)
128 const crashDumpsAllThreadsSource
= `
140 runtime.GOMAXPROCS(count + 1)
142 chans := make([]chan bool, count)
143 for i := range chans {
144 chans[i] = make(chan bool)
148 // Wait for all the goroutines to start executing.
149 for _, c := range chans {
153 time.Sleep(time.Millisecond)
155 // Tell our parent that all the goroutines are executing.
156 if _, err := os.NewFile(3, "pipe").WriteString("x"); err != nil {
157 fmt.Fprintf(os.Stderr, "write to pipe failed: %v\n", err)
164 func loop(i int, c chan bool) {
167 for j := 0; j < 0x7fffffff; j++ {
173 func TestPanicSystemstack(t
*testing
.T
) {
174 // Test that GOTRACEBACK=crash prints both the system and user
175 // stack of other threads.
177 // The GOTRACEBACK=crash handler takes 0.1 seconds even if
178 // it's not writing a core file and potentially much longer if
179 // it is. Skip in short mode.
181 t
.Skip("Skipping in short mode (GOTRACEBACK=crash is slow)")
184 if runtime
.Sigisblocked(int(syscall
.SIGQUIT
)) {
185 t
.Skip("skipping; SIGQUIT is blocked, see golang.org/issue/19196")
189 cmd
:= exec
.Command(os
.Args
[0], "testPanicSystemstackInternal")
190 cmd
= testenv
.CleanCmdEnv(cmd
)
191 cmd
.Env
= append(cmd
.Env
, "GOTRACEBACK=crash")
192 pr
, pw
, err
:= os
.Pipe()
194 t
.Fatal("creating pipe: ", err
)
197 if err
:= cmd
.Start(); err
!= nil {
198 t
.Fatal("starting command: ", err
)
200 defer cmd
.Process
.Wait()
201 defer cmd
.Process
.Kill()
202 if err
:= pw
.Close(); err
!= nil {
203 t
.Log("closing write pipe: ", err
)
207 // Wait for "x\nx\n" to indicate readiness.
208 buf
:= make([]byte, 4)
209 _
, err
= io
.ReadFull(pr
, buf
)
210 if err
!= nil ||
string(buf
) != "x\nx\n" {
211 t
.Fatal("subprocess failed; output:\n", string(buf
))
215 if err
:= cmd
.Process
.Signal(syscall
.SIGQUIT
); err
!= nil {
216 t
.Fatal("signaling subprocess: ", err
)
220 tb
, err
:= ioutil
.ReadAll(pr
)
222 t
.Fatal("reading traceback from pipe: ", err
)
225 // Traceback should have two testPanicSystemstackInternal's
226 // and two blockOnSystemStackInternal's.
227 if bytes
.Count(tb
, []byte("testPanicSystemstackInternal")) != 2 {
228 t
.Fatal("traceback missing user stack:\n", string(tb
))
229 } else if bytes
.Count(tb
, []byte("blockOnSystemStackInternal")) != 2 {
230 t
.Fatal("traceback missing system stack:\n", string(tb
))
235 if len(os
.Args
) >= 2 && os
.Args
[1] == "testPanicSystemstackInternal" {
236 // Get two threads running on the system stack with
237 // something recognizable in the stack trace.
238 runtime
.GOMAXPROCS(2)
239 go testPanicSystemstackInternal()
240 testPanicSystemstackInternal()
244 func testPanicSystemstackInternal() {
245 runtime
.BlockOnSystemStack()
246 os
.Exit(1) // Should be unreachable.
249 func TestSignalExitStatus(t
*testing
.T
) {
250 testenv
.MustHaveGoBuild(t
)
251 exe
, err
:= buildTestProg(t
, "testprog")
255 err
= testenv
.CleanCmdEnv(exec
.Command(exe
, "SignalExitStatus")).Run()
257 t
.Error("test program succeeded unexpectedly")
258 } else if ee
, ok
:= err
.(*exec
.ExitError
); !ok
{
259 t
.Errorf("error (%v) has type %T; expected exec.ExitError", err
, err
)
260 } else if ws
, ok
:= ee
.Sys().(syscall
.WaitStatus
); !ok
{
261 t
.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee
.Sys(), ee
.Sys())
262 } else if !ws
.Signaled() || ws
.Signal() != syscall
.SIGTERM
{
263 t
.Errorf("got %v; expected SIGTERM", ee
)
267 func TestSignalIgnoreSIGTRAP(t
*testing
.T
) {
268 output
:= runTestProg(t
, "testprognet", "SignalIgnoreSIGTRAP")
271 t
.Fatalf("want %s, got %s\n", want
, output
)
275 func TestSignalDuringExec(t
*testing
.T
) {
276 switch runtime
.GOOS
{
277 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
279 t
.Skipf("skipping test on %s", runtime
.GOOS
)
281 output
:= runTestProg(t
, "testprognet", "SignalDuringExec")
284 t
.Fatalf("want %s, got %s\n", want
, output
)