blob: b763a10741746eeec64f2ccde024a469a9c3ce2e [file] [log] [blame]
Russ Cox57eb06f2012-02-16 23:51:04 -05001// run
Russ Coxb6ad0742010-03-31 11:47:09 -07002
3// Copyright 2010 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7// Test of recover during recursive panics.
8// Here be dragons.
9
10package main
11
12import "runtime"
13
14func main() {
15 test1()
16 test2()
17 test3()
18 test4()
19 test5()
20 test6()
21 test7()
22}
23
24func die() {
25 runtime.Breakpoint() // can't depend on panic
26}
27
28func mustRecover(x interface{}) {
29 mustNotRecover() // because it's not a defer call
30 v := recover()
31 if v == nil {
32 println("missing recover")
33 die() // panic is useless here
34 }
35 if v != x {
36 println("wrong value", v, x)
37 die()
38 }
39
40 // the value should be gone now regardless
41 v = recover()
42 if v != nil {
43 println("recover didn't recover")
44 die()
45 }
46}
47
48func mustNotRecover() {
49 v := recover()
50 if v != nil {
51 println("spurious recover")
52 die()
53 }
54}
55
56func withoutRecover() {
57 mustNotRecover() // because it's a sub-call
58}
59
60func test1() {
61 // Easy nested recursive panic.
62 defer mustRecover(1)
63 defer func() {
64 defer mustRecover(2)
65 panic(2)
66 }()
67 panic(1)
68}
69
70func test2() {
71 // Sequential panic.
72 defer mustNotRecover()
73 defer func() {
74 v := recover()
75 if v == nil || v.(int) != 2 {
76 println("wrong value", v, 2)
77 die()
78 }
79 defer mustRecover(3)
80 panic(3)
81 }()
82 panic(2)
83}
84
85func test3() {
86 // Sequential panic - like test2 but less picky.
87 defer mustNotRecover()
88 defer func() {
89 recover()
90 defer mustRecover(3)
91 panic(3)
92 }()
93 panic(2)
94}
95
96func test4() {
97 // Single panic.
98 defer mustNotRecover()
99 defer func() {
100 recover()
101 }()
102 panic(4)
103}
104
105func test5() {
106 // Single panic but recover called via defer
107 defer mustNotRecover()
108 defer func() {
109 defer recover()
110 }()
111 panic(5)
112}
113
114func test6() {
115 // Sequential panic.
116 // Like test3, but changed recover to defer (same change as test4 → test5).
117 defer mustNotRecover()
118 defer func() {
119 defer recover() // like a normal call from this func; runs because mustRecover stops the panic
120 defer mustRecover(3)
121 panic(3)
122 }()
123 panic(2)
124}
125
126func test7() {
127 // Like test6, but swapped defer order.
128 // The recover in "defer recover()" is now a no-op,
129 // because it runs called from panic, not from the func,
130 // and therefore cannot see the panic of 2.
131 // (Alternately, it cannot see the panic of 2 because
132 // there is an active panic of 3. And it cannot see the
133 // panic of 3 because it is at the wrong level (too high on the stack).)
134 defer mustRecover(2)
135 defer func() {
136 defer mustRecover(3)
137 defer recover() // now a no-op, unlike in test6.
138 panic(3)
139 }()
140 panic(2)
141}