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 //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
25 if runtime
.Sigisblocked(int(syscall
.SIGQUIT
)) {
26 // We can't use SIGQUIT to kill subprocesses because
27 // it's blocked. Use SIGKILL instead. See issue
28 // #19196 for an example of when this happens.
29 testenv
.Sigquit
= syscall
.SIGKILL
33 func TestBadOpen(t
*testing
.T
) {
34 // make sure we get the correct error code if open fails. Same for
35 // read/write/close on the resulting -1 fd. See issue 10052.
36 nonfile
:= []byte("/notreallyafile")
37 fd
:= runtime
.Open(&nonfile
[0], 0, 0)
39 t
.Errorf("open(%q)=%d, want -1", nonfile
, fd
)
42 r
:= runtime
.Read(-1, unsafe
.Pointer(&buf
[0]), int32(len(buf
)))
43 if got
, want
:= r
, -int32(syscall
.EBADF
); got
!= want
{
44 t
.Errorf("read()=%d, want %d", got
, want
)
46 w
:= runtime
.Write(^uintptr(0), unsafe
.Pointer(&buf
[0]), int32(len(buf
)))
47 if got
, want
:= w
, -int32(syscall
.EBADF
); got
!= want
{
48 t
.Errorf("write()=%d, want %d", got
, want
)
50 c
:= runtime
.Close(-1)
52 t
.Errorf("close()=%d, want -1", c
)
56 func TestCrashDumpsAllThreads(t
*testing
.T
) {
62 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "illumos", "solaris":
64 t
.Skipf("skipping; not supported on %v", runtime
.GOOS
)
67 if runtime
.GOOS
== "openbsd" && (runtime
.GOARCH
== "arm" || runtime
.GOARCH
== "mips64") {
68 // This may be ncpu < 2 related...
69 t
.Skipf("skipping; test fails on %s/%s - see issue #42464", runtime
.GOOS
, runtime
.GOARCH
)
72 if runtime
.Sigisblocked(int(syscall
.SIGQUIT
)) {
73 t
.Skip("skipping; SIGQUIT is blocked, see golang.org/issue/19196")
76 testenv
.MustHaveGoBuild(t
)
78 exe
, err
:= buildTestProg(t
, "testprog")
83 cmd
:= exec
.Command(exe
, "CrashDumpsAllThreads")
84 cmd
= testenv
.CleanCmdEnv(cmd
)
85 cmd
.Env
= append(cmd
.Env
,
87 // Set GOGC=off. Because of golang.org/issue/10958, the tight
88 // loops in the test program are not preemptible. If GC kicks
89 // in, it may lock up and prevent main from saying it's ready.
91 // Set GODEBUG=asyncpreemptoff=1. If a thread is preempted
92 // when it receives SIGQUIT, it won't show the expected
93 // stack trace. See issue 35356.
94 "GODEBUG=asyncpreemptoff=1",
97 var outbuf bytes
.Buffer
101 rp
, wp
, err
:= os
.Pipe()
107 cmd
.ExtraFiles
= []*os
.File
{wp
}
109 if err
:= cmd
.Start(); err
!= nil {
111 t
.Fatalf("starting program: %v", err
)
114 if err
:= wp
.Close(); err
!= nil {
115 t
.Logf("closing write pipe: %v", err
)
117 if _
, err
:= rp
.Read(make([]byte, 1)); err
!= nil {
118 t
.Fatalf("reading from pipe: %v", err
)
121 if err
:= cmd
.Process
.Signal(syscall
.SIGQUIT
); err
!= nil {
122 t
.Fatalf("signal: %v", err
)
125 // No point in checking the error return from Wait--we expect
129 // We want to see a stack trace for each thread.
130 // Before https://golang.org/cl/2811 running threads would say
131 // "goroutine running on other thread; stack unavailable".
132 out
:= outbuf
.Bytes()
133 n
:= bytes
.Count(out
, []byte("main.crashDumpsAllThreadsLoop"))
135 t
.Errorf("found %d instances of main.crashDumpsAllThreadsLoop; expected 4", n
)
140 func TestPanicSystemstack(t
*testing
.T
) {
141 // Test that GOTRACEBACK=crash prints both the system and user
142 // stack of other threads.
144 // The GOTRACEBACK=crash handler takes 0.1 seconds even if
145 // it's not writing a core file and potentially much longer if
146 // it is. Skip in short mode.
148 t
.Skip("Skipping in short mode (GOTRACEBACK=crash is slow)")
151 if runtime
.Sigisblocked(int(syscall
.SIGQUIT
)) {
152 t
.Skip("skipping; SIGQUIT is blocked, see golang.org/issue/19196")
156 cmd
:= exec
.Command(os
.Args
[0], "testPanicSystemstackInternal")
157 cmd
= testenv
.CleanCmdEnv(cmd
)
158 cmd
.Env
= append(cmd
.Env
, "GOTRACEBACK=crash")
159 pr
, pw
, err
:= os
.Pipe()
161 t
.Fatal("creating pipe: ", err
)
164 if err
:= cmd
.Start(); err
!= nil {
165 t
.Fatal("starting command: ", err
)
167 defer cmd
.Process
.Wait()
168 defer cmd
.Process
.Kill()
169 if err
:= pw
.Close(); err
!= nil {
170 t
.Log("closing write pipe: ", err
)
174 // Wait for "x\nx\n" to indicate almost-readiness.
175 buf
:= make([]byte, 4)
176 _
, err
= io
.ReadFull(pr
, buf
)
177 if err
!= nil ||
string(buf
) != "x\nx\n" {
178 t
.Fatal("subprocess failed; output:\n", string(buf
))
181 // The child blockers print "x\n" and then block on a lock. Receiving
182 // those bytes only indicates that the child is _about to block_. Since
183 // we don't have a way to know when it is fully blocked, sleep a bit to
184 // make us less likely to lose the race and signal before the child
186 time
.Sleep(100 * time
.Millisecond
)
189 if err
:= cmd
.Process
.Signal(syscall
.SIGQUIT
); err
!= nil {
190 t
.Fatal("signaling subprocess: ", err
)
194 tb
, err
:= io
.ReadAll(pr
)
196 t
.Fatal("reading traceback from pipe: ", err
)
199 // Traceback should have two testPanicSystemstackInternal's
200 // and two blockOnSystemStackInternal's.
201 if bytes
.Count(tb
, []byte("testPanicSystemstackInternal")) != 2 {
202 t
.Fatal("traceback missing user stack:\n", string(tb
))
203 } else if bytes
.Count(tb
, []byte("blockOnSystemStackInternal")) != 2 {
204 t
.Fatal("traceback missing system stack:\n", string(tb
))
209 if len(os
.Args
) >= 2 && os
.Args
[1] == "testPanicSystemstackInternal" {
210 // Complete any in-flight GCs and disable future ones. We're going to
211 // block goroutines on runtime locks, which aren't ever preemptible for the
214 debug
.SetGCPercent(-1)
215 // Get two threads running on the system stack with
216 // something recognizable in the stack trace.
217 runtime
.GOMAXPROCS(2)
218 go testPanicSystemstackInternal()
219 testPanicSystemstackInternal()
223 func testPanicSystemstackInternal() {
224 runtime
.BlockOnSystemStack()
225 os
.Exit(1) // Should be unreachable.
228 func TestSignalExitStatus(t
*testing
.T
) {
229 testenv
.MustHaveGoBuild(t
)
230 exe
, err
:= buildTestProg(t
, "testprog")
234 err
= testenv
.CleanCmdEnv(exec
.Command(exe
, "SignalExitStatus")).Run()
236 t
.Error("test program succeeded unexpectedly")
237 } else if ee
, ok
:= err
.(*exec
.ExitError
); !ok
{
238 t
.Errorf("error (%v) has type %T; expected exec.ExitError", err
, err
)
239 } else if ws
, ok
:= ee
.Sys().(syscall
.WaitStatus
); !ok
{
240 t
.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee
.Sys(), ee
.Sys())
241 } else if !ws
.Signaled() || ws
.Signal() != syscall
.SIGTERM
{
242 t
.Errorf("got %v; expected SIGTERM", ee
)
246 func TestSignalIgnoreSIGTRAP(t
*testing
.T
) {
247 if runtime
.GOOS
== "openbsd" {
248 testenv
.SkipFlaky(t
, 49725)
251 output
:= runTestProg(t
, "testprognet", "SignalIgnoreSIGTRAP")
254 t
.Fatalf("want %s, got %s\n", want
, output
)
258 func TestSignalDuringExec(t
*testing
.T
) {
259 switch runtime
.GOOS
{
260 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
262 t
.Skipf("skipping test on %s", runtime
.GOOS
)
264 output
:= runTestProg(t
, "testprognet", "SignalDuringExec")
267 t
.Fatalf("want %s, got %s\n", want
, output
)
271 func TestSignalM(t
*testing
.T
) {
272 if runtime
.Compiler
== "gccgo" {
273 t
.Skip("no signalM for gccgo")
276 r
, w
, errno
:= runtime
.Pipe()
278 t
.Fatal(syscall
.Errno(errno
))
284 runtime
.Closeonexec(r
)
285 runtime
.Closeonexec(w
)
288 var wg sync
.WaitGroup
289 ready
:= make(chan *runtime
.M
)
292 runtime
.LockOSThread()
293 want
, got
= runtime
.WaitForSigusr1(r
, w
, func(mp
*runtime
.M
) {
296 runtime
.UnlockOSThread()
300 runtime
.SendSigusr1(waitingM
)
302 timer
:= time
.AfterFunc(time
.Second
, func() {
303 // Write 1 to tell WaitForSigusr1 that we timed out.
305 if n
:= runtime
.Write(uintptr(w
), unsafe
.Pointer(&bw
), 1); n
!= 1 {
306 t
.Errorf("pipe write failed: %d", n
)
313 t
.Fatal("signalM signal not received")
314 } else if want
!= got
{
315 t
.Fatalf("signal sent to M %d, but received on M %d", want
, got
)