github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/crash_test.go (about) 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 "strings" 13 "testing" 14 "text/template" 15 ) 16 17 // testEnv excludes GOGCTRACE from the environment 18 // to prevent its output from breaking tests that 19 // are trying to parse other command output. 20 func testEnv(cmd *exec.Cmd) *exec.Cmd { 21 if cmd.Env != nil { 22 panic("environment already set") 23 } 24 for _, env := range os.Environ() { 25 if strings.HasPrefix(env, "GOGCTRACE=") { 26 continue 27 } 28 cmd.Env = append(cmd.Env, env) 29 } 30 return cmd 31 } 32 33 func executeTest(t *testing.T, templ string, data interface{}) string { 34 checkStaleRuntime(t) 35 36 st := template.Must(template.New("crashSource").Parse(templ)) 37 38 dir, err := ioutil.TempDir("", "go-build") 39 if err != nil { 40 t.Fatalf("failed to create temp directory: %v", err) 41 } 42 defer os.RemoveAll(dir) 43 44 src := filepath.Join(dir, "main.go") 45 f, err := os.Create(src) 46 if err != nil { 47 t.Fatalf("failed to create %v: %v", src, err) 48 } 49 err = st.Execute(f, data) 50 if err != nil { 51 f.Close() 52 t.Fatalf("failed to execute template: %v", err) 53 } 54 f.Close() 55 56 got, _ := testEnv(exec.Command("go", "run", src)).CombinedOutput() 57 return string(got) 58 } 59 60 func checkStaleRuntime(t *testing.T) { 61 // 'go run' uses the installed copy of runtime.a, which may be out of date. 62 out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput() 63 if err != nil { 64 t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out)) 65 } 66 if string(out) != "false\n" { 67 t.Fatalf("Stale runtime.a. Run 'go install runtime'.") 68 } 69 } 70 71 func testCrashHandler(t *testing.T, cgo bool) { 72 type crashTest struct { 73 Cgo bool 74 } 75 got := executeTest(t, crashSource, &crashTest{Cgo: cgo}) 76 want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n" 77 if got != want { 78 t.Fatalf("expected %q, but got %q", want, got) 79 } 80 } 81 82 func TestCrashHandler(t *testing.T) { 83 testCrashHandler(t, false) 84 } 85 86 func testDeadlock(t *testing.T, source string) { 87 got := executeTest(t, source, nil) 88 want := "fatal error: all goroutines are asleep - deadlock!\n" 89 if !strings.HasPrefix(got, want) { 90 t.Fatalf("expected %q, but got %q", want, got) 91 } 92 } 93 94 func TestSimpleDeadlock(t *testing.T) { 95 testDeadlock(t, simpleDeadlockSource) 96 } 97 98 func TestInitDeadlock(t *testing.T) { 99 testDeadlock(t, initDeadlockSource) 100 } 101 102 func TestLockedDeadlock(t *testing.T) { 103 testDeadlock(t, lockedDeadlockSource) 104 } 105 106 func TestLockedDeadlock2(t *testing.T) { 107 testDeadlock(t, lockedDeadlockSource2) 108 } 109 110 func TestGoexitDeadlock(t *testing.T) { 111 got := executeTest(t, goexitDeadlockSource, nil) 112 want := "" 113 if got != want { 114 t.Fatalf("expected %q, but got %q", want, got) 115 } 116 } 117 118 const crashSource = ` 119 package main 120 121 import ( 122 "fmt" 123 "runtime" 124 ) 125 126 {{if .Cgo}} 127 import "C" 128 {{end}} 129 130 func test(name string) { 131 defer func() { 132 if x := recover(); x != nil { 133 fmt.Printf(" recovered") 134 } 135 fmt.Printf(" done\n") 136 }() 137 fmt.Printf("%s:", name) 138 var s *string 139 _ = *s 140 fmt.Print("SHOULD NOT BE HERE") 141 } 142 143 func testInNewThread(name string) { 144 c := make(chan bool) 145 go func() { 146 runtime.LockOSThread() 147 test(name) 148 c <- true 149 }() 150 <-c 151 } 152 153 func main() { 154 runtime.LockOSThread() 155 test("main") 156 testInNewThread("new-thread") 157 testInNewThread("second-new-thread") 158 test("main-again") 159 } 160 ` 161 162 const simpleDeadlockSource = ` 163 package main 164 func main() { 165 select {} 166 } 167 ` 168 169 const initDeadlockSource = ` 170 package main 171 func init() { 172 select {} 173 } 174 func main() { 175 } 176 ` 177 178 const lockedDeadlockSource = ` 179 package main 180 import "runtime" 181 func main() { 182 runtime.LockOSThread() 183 select {} 184 } 185 ` 186 187 const lockedDeadlockSource2 = ` 188 package main 189 import ( 190 "runtime" 191 "time" 192 ) 193 func main() { 194 go func() { 195 runtime.LockOSThread() 196 select {} 197 }() 198 time.Sleep(time.Millisecond) 199 select {} 200 } 201 ` 202 203 const goexitDeadlockSource = ` 204 package main 205 import ( 206 "runtime" 207 ) 208 209 func F() { 210 for i := 0; i < 10; i++ { 211 } 212 } 213 214 func main() { 215 go F() 216 go F() 217 runtime.Goexit() 218 } 219 `