crash_test.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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. package runtime_test
  5. import (
  6. "io/ioutil"
  7. "os"
  8. "os/exec"
  9. "path/filepath"
  10. "runtime"
  11. "strings"
  12. "testing"
  13. "text/template"
  14. )
  15. // testEnv excludes GODEBUG from the environment
  16. // to prevent its output from breaking tests that
  17. // are trying to parse other command output.
  18. func testEnv(cmd *exec.Cmd) *exec.Cmd {
  19. if cmd.Env != nil {
  20. panic("environment already set")
  21. }
  22. for _, env := range os.Environ() {
  23. if strings.HasPrefix(env, "GODEBUG=") {
  24. continue
  25. }
  26. cmd.Env = append(cmd.Env, env)
  27. }
  28. return cmd
  29. }
  30. func executeTest(t *testing.T, templ string, data interface{}, extra ...string) string {
  31. t.Skip("gccgo does not have a go command")
  32. switch runtime.GOOS {
  33. case "android", "nacl":
  34. t.Skipf("skipping on %s", runtime.GOOS)
  35. }
  36. checkStaleRuntime(t)
  37. st := template.Must(template.New("crashSource").Parse(templ))
  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. src := filepath.Join(dir, "main.go")
  44. f, err := os.Create(src)
  45. if err != nil {
  46. t.Fatalf("failed to create file: %v", err)
  47. }
  48. err = st.Execute(f, data)
  49. if err != nil {
  50. f.Close()
  51. t.Fatalf("failed to execute template: %v", err)
  52. }
  53. if err := f.Close(); err != nil {
  54. t.Fatalf("failed to close file: %v", err)
  55. }
  56. for i := 0; i < len(extra); i += 2 {
  57. if err := ioutil.WriteFile(filepath.Join(dir, extra[i]), []byte(extra[i+1]), 0666); err != nil {
  58. t.Fatal(err)
  59. }
  60. }
  61. cmd := exec.Command("go", "build", "-o", "a.exe")
  62. cmd.Dir = dir
  63. out, err := testEnv(cmd).CombinedOutput()
  64. if err != nil {
  65. t.Fatalf("building source: %v\n%s", err, out)
  66. }
  67. got, _ := testEnv(exec.Command(filepath.Join(dir, "a.exe"))).CombinedOutput()
  68. return string(got)
  69. }
  70. func checkStaleRuntime(t *testing.T) {
  71. // 'go run' uses the installed copy of runtime.a, which may be out of date.
  72. out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
  73. if err != nil {
  74. t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out))
  75. }
  76. if string(out) != "false\n" {
  77. t.Fatalf("Stale runtime.a. Run 'go install runtime'.")
  78. }
  79. }
  80. func testCrashHandler(t *testing.T, cgo bool) {
  81. type crashTest struct {
  82. Cgo bool
  83. }
  84. output := executeTest(t, crashSource, &crashTest{Cgo: cgo})
  85. want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
  86. if output != want {
  87. t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
  88. }
  89. }
  90. func TestCrashHandler(t *testing.T) {
  91. testCrashHandler(t, false)
  92. }
  93. func testDeadlock(t *testing.T, source string) {
  94. output := executeTest(t, source, nil)
  95. want := "fatal error: all goroutines are asleep - deadlock!\n"
  96. if !strings.HasPrefix(output, want) {
  97. t.Fatalf("output does not start with %q:\n%s", want, output)
  98. }
  99. }
  100. func TestSimpleDeadlock(t *testing.T) {
  101. testDeadlock(t, simpleDeadlockSource)
  102. }
  103. func TestInitDeadlock(t *testing.T) {
  104. testDeadlock(t, initDeadlockSource)
  105. }
  106. func TestLockedDeadlock(t *testing.T) {
  107. testDeadlock(t, lockedDeadlockSource)
  108. }
  109. func TestLockedDeadlock2(t *testing.T) {
  110. testDeadlock(t, lockedDeadlockSource2)
  111. }
  112. func TestGoexitDeadlock(t *testing.T) {
  113. output := executeTest(t, goexitDeadlockSource, nil)
  114. want := "no goroutines (main called runtime.Goexit) - deadlock!"
  115. if !strings.Contains(output, want) {
  116. t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
  117. }
  118. }
  119. func TestStackOverflow(t *testing.T) {
  120. output := executeTest(t, stackOverflowSource, nil)
  121. want := "runtime: goroutine stack exceeds 4194304-byte limit\nfatal error: stack overflow"
  122. if !strings.HasPrefix(output, want) {
  123. t.Fatalf("output does not start with %q:\n%s", want, output)
  124. }
  125. }
  126. func TestThreadExhaustion(t *testing.T) {
  127. output := executeTest(t, threadExhaustionSource, nil)
  128. want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
  129. if !strings.HasPrefix(output, want) {
  130. t.Fatalf("output does not start with %q:\n%s", want, output)
  131. }
  132. }
  133. func TestRecursivePanic(t *testing.T) {
  134. output := executeTest(t, recursivePanicSource, nil)
  135. want := `wrap: bad
  136. panic: again
  137. `
  138. if !strings.HasPrefix(output, want) {
  139. t.Fatalf("output does not start with %q:\n%s", want, output)
  140. }
  141. }
  142. func TestGoexitCrash(t *testing.T) {
  143. output := executeTest(t, goexitExitSource, nil)
  144. want := "no goroutines (main called runtime.Goexit) - deadlock!"
  145. if !strings.Contains(output, want) {
  146. t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
  147. }
  148. }
  149. func TestGoexitDefer(t *testing.T) {
  150. c := make(chan struct{})
  151. go func() {
  152. defer func() {
  153. r := recover()
  154. if r != nil {
  155. t.Errorf("non-nil recover during Goexit")
  156. }
  157. c <- struct{}{}
  158. }()
  159. runtime.Goexit()
  160. }()
  161. // Note: if the defer fails to run, we will get a deadlock here
  162. <-c
  163. }
  164. func TestGoNil(t *testing.T) {
  165. output := executeTest(t, goNilSource, nil)
  166. want := "go of nil func value"
  167. if !strings.Contains(output, want) {
  168. t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
  169. }
  170. }
  171. func TestMainGoroutineId(t *testing.T) {
  172. output := executeTest(t, mainGoroutineIdSource, nil)
  173. want := "panic: test\n\ngoroutine 1 [running]:\n"
  174. if !strings.HasPrefix(output, want) {
  175. t.Fatalf("output does not start with %q:\n%s", want, output)
  176. }
  177. }
  178. func TestBreakpoint(t *testing.T) {
  179. output := executeTest(t, breakpointSource, nil)
  180. want := "runtime.Breakpoint()"
  181. if !strings.Contains(output, want) {
  182. t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
  183. }
  184. }
  185. const crashSource = `
  186. package main
  187. import (
  188. "fmt"
  189. "runtime"
  190. )
  191. {{if .Cgo}}
  192. import "C"
  193. {{end}}
  194. func test(name string) {
  195. defer func() {
  196. if x := recover(); x != nil {
  197. fmt.Printf(" recovered")
  198. }
  199. fmt.Printf(" done\n")
  200. }()
  201. fmt.Printf("%s:", name)
  202. var s *string
  203. _ = *s
  204. fmt.Print("SHOULD NOT BE HERE")
  205. }
  206. func testInNewThread(name string) {
  207. c := make(chan bool)
  208. go func() {
  209. runtime.LockOSThread()
  210. test(name)
  211. c <- true
  212. }()
  213. <-c
  214. }
  215. func main() {
  216. runtime.LockOSThread()
  217. test("main")
  218. testInNewThread("new-thread")
  219. testInNewThread("second-new-thread")
  220. test("main-again")
  221. }
  222. `
  223. const simpleDeadlockSource = `
  224. package main
  225. func main() {
  226. select {}
  227. }
  228. `
  229. const initDeadlockSource = `
  230. package main
  231. func init() {
  232. select {}
  233. }
  234. func main() {
  235. }
  236. `
  237. const lockedDeadlockSource = `
  238. package main
  239. import "runtime"
  240. func main() {
  241. runtime.LockOSThread()
  242. select {}
  243. }
  244. `
  245. const lockedDeadlockSource2 = `
  246. package main
  247. import (
  248. "runtime"
  249. "time"
  250. )
  251. func main() {
  252. go func() {
  253. runtime.LockOSThread()
  254. select {}
  255. }()
  256. time.Sleep(time.Millisecond)
  257. select {}
  258. }
  259. `
  260. const goexitDeadlockSource = `
  261. package main
  262. import (
  263. "runtime"
  264. )
  265. func F() {
  266. for i := 0; i < 10; i++ {
  267. }
  268. }
  269. func main() {
  270. go F()
  271. go F()
  272. runtime.Goexit()
  273. }
  274. `
  275. const stackOverflowSource = `
  276. package main
  277. import "runtime/debug"
  278. func main() {
  279. debug.SetMaxStack(4<<20)
  280. f(make([]byte, 10))
  281. }
  282. func f(x []byte) byte {
  283. var buf [64<<10]byte
  284. return x[0] + f(buf[:])
  285. }
  286. `
  287. const threadExhaustionSource = `
  288. package main
  289. import (
  290. "runtime"
  291. "runtime/debug"
  292. )
  293. func main() {
  294. debug.SetMaxThreads(10)
  295. c := make(chan int)
  296. for i := 0; i < 100; i++ {
  297. go func() {
  298. runtime.LockOSThread()
  299. c <- 0
  300. select{}
  301. }()
  302. <-c
  303. }
  304. }
  305. `
  306. const recursivePanicSource = `
  307. package main
  308. import (
  309. "fmt"
  310. )
  311. func main() {
  312. func() {
  313. defer func() {
  314. fmt.Println(recover())
  315. }()
  316. var x [8192]byte
  317. func(x [8192]byte) {
  318. defer func() {
  319. if err := recover(); err != nil {
  320. panic("wrap: " + err.(string))
  321. }
  322. }()
  323. panic("bad")
  324. }(x)
  325. }()
  326. panic("again")
  327. }
  328. `
  329. const goexitExitSource = `
  330. package main
  331. import (
  332. "runtime"
  333. "time"
  334. )
  335. func main() {
  336. go func() {
  337. time.Sleep(time.Millisecond)
  338. }()
  339. i := 0
  340. runtime.SetFinalizer(&i, func(p *int) {})
  341. runtime.GC()
  342. runtime.Goexit()
  343. }
  344. `
  345. const goNilSource = `
  346. package main
  347. func main() {
  348. defer func() {
  349. recover()
  350. }()
  351. var f func()
  352. go f()
  353. select{}
  354. }
  355. `
  356. const mainGoroutineIdSource = `
  357. package main
  358. func main() {
  359. panic("test")
  360. }
  361. `
  362. const breakpointSource = `
  363. package main
  364. import "runtime"
  365. func main() {
  366. runtime.Breakpoint()
  367. }
  368. `
  369. func TestGoexitInPanic(t *testing.T) {
  370. // see issue 8774: this code used to trigger an infinite recursion
  371. output := executeTest(t, goexitInPanicSource, nil)
  372. want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
  373. if !strings.HasPrefix(output, want) {
  374. t.Fatalf("output does not start with %q:\n%s", want, output)
  375. }
  376. }
  377. const goexitInPanicSource = `
  378. package main
  379. import "runtime"
  380. func main() {
  381. go func() {
  382. defer func() {
  383. runtime.Goexit()
  384. }()
  385. panic("hello")
  386. }()
  387. runtime.Goexit()
  388. }
  389. `
  390. func TestPanicAfterGoexit(t *testing.T) {
  391. // an uncaught panic should still work after goexit
  392. output := executeTest(t, panicAfterGoexitSource, nil)
  393. want := "panic: hello"
  394. if !strings.HasPrefix(output, want) {
  395. t.Fatalf("output does not start with %q:\n%s", want, output)
  396. }
  397. }
  398. const panicAfterGoexitSource = `
  399. package main
  400. import "runtime"
  401. func main() {
  402. defer func() {
  403. panic("hello")
  404. }()
  405. runtime.Goexit()
  406. }
  407. `
  408. func TestRecoveredPanicAfterGoexit(t *testing.T) {
  409. output := executeTest(t, recoveredPanicAfterGoexitSource, nil)
  410. want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
  411. if !strings.HasPrefix(output, want) {
  412. t.Fatalf("output does not start with %q:\n%s", want, output)
  413. }
  414. }
  415. const recoveredPanicAfterGoexitSource = `
  416. package main
  417. import "runtime"
  418. func main() {
  419. defer func() {
  420. defer func() {
  421. r := recover()
  422. if r == nil {
  423. panic("bad recover")
  424. }
  425. }()
  426. panic("hello")
  427. }()
  428. runtime.Goexit()
  429. }
  430. `
  431. func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
  432. // 1. defer a function that recovers
  433. // 2. defer a function that panics
  434. // 3. call goexit
  435. // Goexit should run the #2 defer. Its panic
  436. // should be caught by the #1 defer, and execution
  437. // should resume in the caller. Like the Goexit
  438. // never happened!
  439. defer func() {
  440. r := recover()
  441. if r == nil {
  442. panic("bad recover")
  443. }
  444. }()
  445. defer func() {
  446. panic("hello")
  447. }()
  448. runtime.Goexit()
  449. }