blob: ca6f0728860c7aa3006026695df48cd72a7c2475 [file] [log] [blame]
Russ Coxb6ad0742010-03-31 11:47:09 -07001// $G $D/$F.go && $L $F.$A && ./$A.out
2
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 basic recover functionality.
8
9package main
10
11import "runtime"
12
13func main() {
14 test1()
15 test1WithClosures()
16 test2()
17 test3()
18 test4()
19 test5()
20 test6()
21 test6WithClosures()
22 test7()
23}
24
25func die() {
Russ Coxf75d0d22010-04-01 22:31:27 -070026 runtime.Breakpoint() // can't depend on panic
Russ Coxb6ad0742010-03-31 11:47:09 -070027}
28
29func mustRecover(x interface{}) {
Russ Coxf75d0d22010-04-01 22:31:27 -070030 mustNotRecover() // because it's not a defer call
Russ Coxb6ad0742010-03-31 11:47:09 -070031 v := recover()
32 if v == nil {
33 println("missing recover")
Russ Coxf75d0d22010-04-01 22:31:27 -070034 die() // panic is useless here
Russ Coxb6ad0742010-03-31 11:47:09 -070035 }
36 if v != x {
37 println("wrong value", v, x)
38 die()
39 }
Russ Coxf75d0d22010-04-01 22:31:27 -070040
Russ Coxb6ad0742010-03-31 11:47:09 -070041 // the value should be gone now regardless
42 v = recover()
43 if v != nil {
44 println("recover didn't recover")
45 die()
46 }
47}
48
49func mustNotRecover() {
50 v := recover()
51 if v != nil {
Russ Coxf75d0d22010-04-01 22:31:27 -070052 println("spurious recover", v)
Russ Coxb6ad0742010-03-31 11:47:09 -070053 die()
54 }
55}
56
57func withoutRecover() {
Russ Coxf75d0d22010-04-01 22:31:27 -070058 mustNotRecover() // because it's a sub-call
Russ Coxb6ad0742010-03-31 11:47:09 -070059}
60
61func test1() {
Russ Coxf75d0d22010-04-01 22:31:27 -070062 defer mustNotRecover() // because mustRecover will squelch it
63 defer mustRecover(1) // because of panic below
64 defer withoutRecover() // should be no-op, leaving for mustRecover to find
Russ Coxb6ad0742010-03-31 11:47:09 -070065 panic(1)
66}
67
68// Repeat test1 with closures instead of standard function.
69// Interesting because recover bases its decision
70// on the frame pointer of its caller, and a closure's
71// frame pointer is in the middle of its actual arguments
72// (after the hidden ones for the closed-over variables).
73func test1WithClosures() {
74 defer func() {
75 v := recover()
76 if v != nil {
77 println("spurious recover in closure")
78 die()
79 }
80 }()
81 defer func(x interface{}) {
82 mustNotRecover()
83 v := recover()
84 if v == nil {
85 println("missing recover")
86 die()
87 }
88 if v != x {
89 println("wrong value", v, x)
90 die()
91 }
92 }(1)
93 defer func() {
94 mustNotRecover()
95 }()
96 panic(1)
97}
98
99func test2() {
100 // Recover only sees the panic argument
101 // if it is called from a deferred call.
102 // It does not see the panic when called from a call within a deferred call (too late)
103 // nor does it see the panic when it *is* the deferred call (too early).
104 defer mustRecover(2)
Russ Coxf75d0d22010-04-01 22:31:27 -0700105 defer recover() // should be no-op
Russ Coxb6ad0742010-03-31 11:47:09 -0700106 panic(2)
107}
108
109func test3() {
110 defer mustNotRecover()
111 defer func() {
Russ Coxf75d0d22010-04-01 22:31:27 -0700112 recover() // should squelch
Russ Coxb6ad0742010-03-31 11:47:09 -0700113 }()
114 panic(3)
115}
116
117func test4() {
118 // Equivalent to test3 but using defer to make the call.
119 defer mustNotRecover()
120 defer func() {
Russ Coxf75d0d22010-04-01 22:31:27 -0700121 defer recover() // should squelch
Russ Coxb6ad0742010-03-31 11:47:09 -0700122 }()
123 panic(4)
124}
125
126// Check that closures can set output arguments.
127// Run g(). If it panics, return x; else return deflt.
128func try(g func(), deflt interface{}) (x interface{}) {
129 defer func() {
130 if v := recover(); v != nil {
131 x = v
132 }
133 }()
134 defer g()
135 return deflt
136}
137
138// Check that closures can set output arguments.
139// Run g(). If it panics, return x; else return deflt.
140func try1(g func(), deflt interface{}) (x interface{}) {
141 defer func() {
142 if v := recover(); v != nil {
143 x = v
144 }
145 }()
146 defer g()
147 x = deflt
148 return
149}
150
151func test5() {
152 v := try(func() { panic(5) }, 55).(int)
153 if v != 5 {
154 println("wrong value", v, 5)
155 die()
156 }
Russ Coxf75d0d22010-04-01 22:31:27 -0700157
158 s := try(func() {}, "hi").(string)
Russ Coxb6ad0742010-03-31 11:47:09 -0700159 if s != "hi" {
160 println("wrong value", s, "hi")
161 die()
162 }
163
164 v = try1(func() { panic(5) }, 55).(int)
165 if v != 5 {
166 println("try1 wrong value", v, 5)
167 die()
168 }
Russ Coxf75d0d22010-04-01 22:31:27 -0700169
170 s = try1(func() {}, "hi").(string)
Russ Coxb6ad0742010-03-31 11:47:09 -0700171 if s != "hi" {
172 println("try1 wrong value", s, "hi")
173 die()
174 }
175}
176
177// When a deferred big call starts, it must first
178// create yet another stack segment to hold the
179// giant frame for x. Make sure that doesn't
180// confuse recover.
181func big(mustRecover bool) {
182 var x [100000]int
183 x[0] = 1
184 x[99999] = 1
185 _ = x
Russ Coxf75d0d22010-04-01 22:31:27 -0700186
Russ Coxb6ad0742010-03-31 11:47:09 -0700187 v := recover()
188 if mustRecover {
189 if v == nil {
190 println("missing big recover")
191 die()
192 }
193 } else {
194 if v != nil {
195 println("spurious big recover")
196 die()
197 }
198 }
199}
200
201func test6() {
202 defer big(false)
203 defer big(true)
204 panic(6)
205}
206
207func test6WithClosures() {
208 defer func() {
209 var x [100000]int
210 x[0] = 1
211 x[99999] = 1
212 _ = x
213 if recover() != nil {
214 println("spurious big closure recover")
215 die()
216 }
217 }()
218 defer func() {
219 var x [100000]int
220 x[0] = 1
221 x[99999] = 1
222 _ = x
223 if recover() == nil {
224 println("missing big closure recover")
225 die()
226 }
227 }()
228 panic("6WithClosures")
229}
230
231func test7() {
232 ok := false
233 func() {
234 // should panic, then call mustRecover 7, which stops the panic.
235 // then should keep processing ordinary defers earlier than that one
236 // before returning.
237 // this test checks that the defer func on the next line actually runs.
238 defer func() { ok = true }()
239 defer mustRecover(7)
240 panic(7)
241 }()
242 if !ok {
243 println("did not run ok func")
244 die()
245 }
246}