Revert "[PATCH 7/7] RISC-V: Disable by pieces for vector setmem length > UNITS_PER_WORD"
[official-gcc.git] / libgo / go / runtime / crash_unix_test.go
blobab94affe97f74743240c09f73330621333cc8ef7
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
7 package runtime_test
9 import (
10 "bytes"
11 "internal/testenv"
12 "io"
13 "os"
14 "os/exec"
15 "runtime"
16 "runtime/debug"
17 "sync"
18 "syscall"
19 "testing"
20 "time"
21 "unsafe"
24 func init() {
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)
38 if fd != -1 {
39 t.Errorf("open(%q)=%d, want -1", nonfile, fd)
41 var buf [32]byte
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)
51 if c != -1 {
52 t.Errorf("close()=%d, want -1", c)
56 func TestCrashDumpsAllThreads(t *testing.T) {
57 if *flagQuick {
58 t.Skip("-quick")
61 switch runtime.GOOS {
62 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "illumos", "solaris":
63 default:
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")
79 if err != nil {
80 t.Fatal(err)
83 cmd := exec.Command(exe, "CrashDumpsAllThreads")
84 cmd = testenv.CleanCmdEnv(cmd)
85 cmd.Env = append(cmd.Env,
86 "GOTRACEBACK=crash",
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.
90 "GOGC=off",
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
98 cmd.Stdout = &outbuf
99 cmd.Stderr = &outbuf
101 rp, wp, err := os.Pipe()
102 if err != nil {
103 t.Fatal(err)
105 defer rp.Close()
107 cmd.ExtraFiles = []*os.File{wp}
109 if err := cmd.Start(); err != nil {
110 wp.Close()
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
126 // it to fail.
127 cmd.Wait()
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"))
134 if n != 4 {
135 t.Errorf("found %d instances of main.crashDumpsAllThreadsLoop; expected 4", n)
136 t.Logf("%s", out)
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.
147 if testing.Short() {
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")
155 t.Parallel()
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()
160 if err != nil {
161 t.Fatal("creating pipe: ", err)
163 cmd.Stderr = pw
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)
172 defer pr.Close()
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
185 // blocks.
186 time.Sleep(100 * time.Millisecond)
188 // Send SIGQUIT.
189 if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil {
190 t.Fatal("signaling subprocess: ", err)
193 // Get traceback.
194 tb, err := io.ReadAll(pr)
195 if err != nil {
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))
208 func init() {
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
212 // GC to scan them.
213 runtime.GC()
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")
231 if err != nil {
232 t.Fatal(err)
234 err = testenv.CleanCmdEnv(exec.Command(exe, "SignalExitStatus")).Run()
235 if err == nil {
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")
252 want := "OK\n"
253 if output != want {
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":
261 default:
262 t.Skipf("skipping test on %s", runtime.GOOS)
264 output := runTestProg(t, "testprognet", "SignalDuringExec")
265 want := "OK\n"
266 if output != want {
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()
277 if errno != 0 {
278 t.Fatal(syscall.Errno(errno))
280 defer func() {
281 runtime.Close(r)
282 runtime.Close(w)
284 runtime.Closeonexec(r)
285 runtime.Closeonexec(w)
287 var want, got int64
288 var wg sync.WaitGroup
289 ready := make(chan *runtime.M)
290 wg.Add(1)
291 go func() {
292 runtime.LockOSThread()
293 want, got = runtime.WaitForSigusr1(r, w, func(mp *runtime.M) {
294 ready <- mp
296 runtime.UnlockOSThread()
297 wg.Done()
299 waitingM := <-ready
300 runtime.SendSigusr1(waitingM)
302 timer := time.AfterFunc(time.Second, func() {
303 // Write 1 to tell WaitForSigusr1 that we timed out.
304 bw := byte(1)
305 if n := runtime.Write(uintptr(w), unsafe.Pointer(&bw), 1); n != 1 {
306 t.Errorf("pipe write failed: %d", n)
309 defer timer.Stop()
311 wg.Wait()
312 if got == -1 {
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)