summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/crash_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/crash_test.go')
-rw-r--r--src/pkg/runtime/crash_test.go177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/pkg/runtime/crash_test.go b/src/pkg/runtime/crash_test.go
new file mode 100644
index 000000000..5f84cb5a2
--- /dev/null
+++ b/src/pkg/runtime/crash_test.go
@@ -0,0 +1,177 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+ "text/template"
+)
+
+func executeTest(t *testing.T, templ string, data interface{}) string {
+ checkStaleRuntime(t)
+
+ st := template.Must(template.New("crashSource").Parse(templ))
+
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatalf("failed to create temp directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ src := filepath.Join(dir, "main.go")
+ f, err := os.Create(src)
+ if err != nil {
+ t.Fatalf("failed to create %v: %v", src, err)
+ }
+ err = st.Execute(f, data)
+ if err != nil {
+ f.Close()
+ t.Fatalf("failed to execute template: %v", err)
+ }
+ f.Close()
+
+ got, _ := exec.Command("go", "run", src).CombinedOutput()
+ return string(got)
+}
+
+func checkStaleRuntime(t *testing.T) {
+ // 'go run' uses the installed copy of runtime.a, which may be out of date.
+ out, err := exec.Command("go", "list", "-f", "{{.Stale}}", "runtime").CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out))
+ }
+ if string(out) != "false\n" {
+ t.Fatalf("Stale runtime.a. Run 'go install runtime'.")
+ }
+}
+
+func testCrashHandler(t *testing.T, cgo bool) {
+ type crashTest struct {
+ Cgo bool
+ }
+ got := executeTest(t, crashSource, &crashTest{Cgo: cgo})
+ want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
+ if got != want {
+ t.Fatalf("expected %q, but got %q", want, got)
+ }
+}
+
+func TestCrashHandler(t *testing.T) {
+ testCrashHandler(t, false)
+}
+
+func testDeadlock(t *testing.T, source string) {
+ got := executeTest(t, source, nil)
+ want := "fatal error: all goroutines are asleep - deadlock!\n"
+ if !strings.HasPrefix(got, want) {
+ t.Fatalf("expected %q, but got %q", want, got)
+ }
+}
+
+func TestSimpleDeadlock(t *testing.T) {
+ testDeadlock(t, simpleDeadlockSource)
+}
+
+func TestInitDeadlock(t *testing.T) {
+ testDeadlock(t, initDeadlockSource)
+}
+
+func TestLockedDeadlock(t *testing.T) {
+ testDeadlock(t, lockedDeadlockSource)
+}
+
+func TestLockedDeadlock2(t *testing.T) {
+ testDeadlock(t, lockedDeadlockSource2)
+}
+
+const crashSource = `
+package main
+
+import (
+ "fmt"
+ "runtime"
+)
+
+{{if .Cgo}}
+import "C"
+{{end}}
+
+func test(name string) {
+ defer func() {
+ if x := recover(); x != nil {
+ fmt.Printf(" recovered")
+ }
+ fmt.Printf(" done\n")
+ }()
+ fmt.Printf("%s:", name)
+ var s *string
+ _ = *s
+ fmt.Print("SHOULD NOT BE HERE")
+}
+
+func testInNewThread(name string) {
+ c := make(chan bool)
+ go func() {
+ runtime.LockOSThread()
+ test(name)
+ c <- true
+ }()
+ <-c
+}
+
+func main() {
+ runtime.LockOSThread()
+ test("main")
+ testInNewThread("new-thread")
+ testInNewThread("second-new-thread")
+ test("main-again")
+}
+`
+
+const simpleDeadlockSource = `
+package main
+func main() {
+ select {}
+}
+`
+
+const initDeadlockSource = `
+package main
+func init() {
+ select {}
+}
+func main() {
+}
+`
+
+const lockedDeadlockSource = `
+package main
+import "runtime"
+func main() {
+ runtime.LockOSThread()
+ select {}
+}
+`
+
+const lockedDeadlockSource2 = `
+package main
+import (
+ "runtime"
+ "time"
+)
+func main() {
+ go func() {
+ runtime.LockOSThread()
+ select {}
+ }()
+ time.Sleep(time.Millisecond)
+ select {}
+}
+`