39e04345a10ac968d9f38f92415249d435483b50
[platform/upstream/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         "io/ioutil"
9         "os"
10         "os/exec"
11         "path/filepath"
12         "runtime"
13         "strings"
14         "testing"
15         "text/template"
16 )
17
18 // testEnv excludes GODEBUG from the environment
19 // to prevent its output from breaking tests that
20 // are trying to parse other command output.
21 func testEnv(cmd *exec.Cmd) *exec.Cmd {
22         if cmd.Env != nil {
23                 panic("environment already set")
24         }
25         for _, env := range os.Environ() {
26                 if strings.HasPrefix(env, "GODEBUG=") {
27                         continue
28                 }
29                 cmd.Env = append(cmd.Env, env)
30         }
31         return cmd
32 }
33
34 func executeTest(t *testing.T, templ string, data interface{}) string {
35         t.Skip("gccgo does not have a go command")
36         if runtime.GOOS == "nacl" {
37                 t.Skip("skipping on nacl")
38         }
39
40         checkStaleRuntime(t)
41
42         st := template.Must(template.New("crashSource").Parse(templ))
43
44         dir, err := ioutil.TempDir("", "go-build")
45         if err != nil {
46                 t.Fatalf("failed to create temp directory: %v", err)
47         }
48         defer os.RemoveAll(dir)
49
50         src := filepath.Join(dir, "main.go")
51         f, err := os.Create(src)
52         if err != nil {
53                 t.Fatalf("failed to create file: %v", err)
54         }
55         err = st.Execute(f, data)
56         if err != nil {
57                 f.Close()
58                 t.Fatalf("failed to execute template: %v", err)
59         }
60         if err := f.Close(); err != nil {
61                 t.Fatalf("failed to close file: %v", err)
62         }
63
64         got, _ := testEnv(exec.Command("go", "run", src)).CombinedOutput()
65         return string(got)
66 }
67
68 func checkStaleRuntime(t *testing.T) {
69         // 'go run' uses the installed copy of runtime.a, which may be out of date.
70         out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
71         if err != nil {
72                 t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out))
73         }
74         if string(out) != "false\n" {
75                 t.Fatalf("Stale runtime.a. Run 'go install runtime'.")
76         }
77 }
78
79 func testCrashHandler(t *testing.T, cgo bool) {
80         type crashTest struct {
81                 Cgo bool
82         }
83         output := executeTest(t, crashSource, &crashTest{Cgo: cgo})
84         want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
85         if output != want {
86                 t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
87         }
88 }
89
90 func TestCrashHandler(t *testing.T) {
91         testCrashHandler(t, false)
92 }
93
94 func testDeadlock(t *testing.T, source string) {
95         output := executeTest(t, source, nil)
96         want := "fatal error: all goroutines are asleep - deadlock!\n"
97         if !strings.HasPrefix(output, want) {
98                 t.Fatalf("output does not start with %q:\n%s", want, output)
99         }
100 }
101
102 func TestSimpleDeadlock(t *testing.T) {
103         testDeadlock(t, simpleDeadlockSource)
104 }
105
106 func TestInitDeadlock(t *testing.T) {
107         testDeadlock(t, initDeadlockSource)
108 }
109
110 func TestLockedDeadlock(t *testing.T) {
111         testDeadlock(t, lockedDeadlockSource)
112 }
113
114 func TestLockedDeadlock2(t *testing.T) {
115         testDeadlock(t, lockedDeadlockSource2)
116 }
117
118 func TestGoexitDeadlock(t *testing.T) {
119         output := executeTest(t, goexitDeadlockSource, nil)
120         want := "no goroutines (main called runtime.Goexit) - deadlock!"
121         if !strings.Contains(output, want) {
122                 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
123         }
124 }
125
126 func TestStackOverflow(t *testing.T) {
127         output := executeTest(t, stackOverflowSource, nil)
128         want := "runtime: goroutine stack exceeds 4194304-byte limit\nfatal error: stack overflow"
129         if !strings.HasPrefix(output, want) {
130                 t.Fatalf("output does not start with %q:\n%s", want, output)
131         }
132 }
133
134 func TestThreadExhaustion(t *testing.T) {
135         output := executeTest(t, threadExhaustionSource, nil)
136         want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
137         if !strings.HasPrefix(output, want) {
138                 t.Fatalf("output does not start with %q:\n%s", want, output)
139         }
140 }
141
142 func TestRecursivePanic(t *testing.T) {
143         output := executeTest(t, recursivePanicSource, nil)
144         want := `wrap: bad
145 panic: again
146
147 `
148         if !strings.HasPrefix(output, want) {
149                 t.Fatalf("output does not start with %q:\n%s", want, output)
150         }
151
152 }
153
154 func TestGoexitCrash(t *testing.T) {
155         output := executeTest(t, goexitExitSource, nil)
156         want := "no goroutines (main called runtime.Goexit) - deadlock!"
157         if !strings.Contains(output, want) {
158                 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
159         }
160 }
161
162 func TestGoNil(t *testing.T) {
163         output := executeTest(t, goNilSource, nil)
164         want := "go of nil func value"
165         if !strings.Contains(output, want) {
166                 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
167         }
168 }
169
170 const crashSource = `
171 package main
172
173 import (
174         "fmt"
175         "runtime"
176 )
177
178 {{if .Cgo}}
179 import "C"
180 {{end}}
181
182 func test(name string) {
183         defer func() {
184                 if x := recover(); x != nil {
185                         fmt.Printf(" recovered")
186                 }
187                 fmt.Printf(" done\n")
188         }()
189         fmt.Printf("%s:", name)
190         var s *string
191         _ = *s
192         fmt.Print("SHOULD NOT BE HERE")
193 }
194
195 func testInNewThread(name string) {
196         c := make(chan bool)
197         go func() {
198                 runtime.LockOSThread()
199                 test(name)
200                 c <- true
201         }()
202         <-c
203 }
204
205 func main() {
206         runtime.LockOSThread()
207         test("main")
208         testInNewThread("new-thread")
209         testInNewThread("second-new-thread")
210         test("main-again")
211 }
212 `
213
214 const simpleDeadlockSource = `
215 package main
216 func main() {
217         select {}
218 }
219 `
220
221 const initDeadlockSource = `
222 package main
223 func init() {
224         select {}
225 }
226 func main() {
227 }
228 `
229
230 const lockedDeadlockSource = `
231 package main
232 import "runtime"
233 func main() {
234         runtime.LockOSThread()
235         select {}
236 }
237 `
238
239 const lockedDeadlockSource2 = `
240 package main
241 import (
242         "runtime"
243         "time"
244 )
245 func main() {
246         go func() {
247                 runtime.LockOSThread()
248                 select {}
249         }()
250         time.Sleep(time.Millisecond)
251         select {}
252 }
253 `
254
255 const goexitDeadlockSource = `
256 package main
257 import (
258       "runtime"
259 )
260
261 func F() {
262       for i := 0; i < 10; i++ {
263       }
264 }
265
266 func main() {
267       go F()
268       go F()
269       runtime.Goexit()
270 }
271 `
272
273 const stackOverflowSource = `
274 package main
275
276 import "runtime/debug"
277
278 func main() {
279         debug.SetMaxStack(4<<20)
280         f(make([]byte, 10))
281 }
282
283 func f(x []byte) byte {
284         var buf [64<<10]byte
285         return x[0] + f(buf[:])
286 }
287 `
288
289 const threadExhaustionSource = `
290 package main
291
292 import (
293         "runtime"
294         "runtime/debug"
295 )
296
297 func main() {
298         debug.SetMaxThreads(10)
299         c := make(chan int)
300         for i := 0; i < 100; i++ {
301                 go func() {
302                         runtime.LockOSThread()
303                         c <- 0
304                         select{}
305                 }()
306                 <-c
307         }
308 }
309 `
310
311 const recursivePanicSource = `
312 package main
313
314 import (
315         "fmt"
316 )
317
318 func main() {
319         func() {
320                 defer func() {
321                         fmt.Println(recover())
322                 }()
323                 var x [8192]byte
324                 func(x [8192]byte) {
325                         defer func() {
326                                 if err := recover(); err != nil {
327                                         panic("wrap: " + err.(string))
328                                 }
329                         }()
330                         panic("bad")
331                 }(x)
332         }()
333         panic("again")
334 }
335 `
336
337 const goexitExitSource = `
338 package main
339
340 import (
341         "runtime"
342         "time"
343 )
344
345 func main() {
346         go func() {
347                 time.Sleep(time.Millisecond)
348         }()
349         i := 0
350         runtime.SetFinalizer(&i, func(p *int) {})
351         runtime.GC()
352         runtime.Goexit()
353 }
354 `
355
356 const goNilSource = `
357 package main
358
359 func main() {
360         defer func() {
361                 recover()
362         }()
363         var f func()
364         go f()
365         select{}
366 }
367 `