blob: 6287d65076d333eb7157d5c148040986e75a38f4 [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 basic recover functionality.
8
9package main
10
Alan Donovanaa5aaab2013-02-21 12:48:38 -050011import (
12 "os"
Russ Cox7276c022013-09-12 14:00:16 -040013 "reflect"
Alan Donovanaa5aaab2013-02-21 12:48:38 -050014 "runtime"
15)
Russ Coxb6ad0742010-03-31 11:47:09 -070016
17func main() {
Alan Donovan3ddf5a62013-09-18 14:44:57 -040018 // go.tools/ssa/interp still has:
19 // - some lesser bugs in recover()
20 // - incomplete support for reflection
21 interp := os.Getenv("GOSSAINTERP") != ""
22
Russ Coxb6ad0742010-03-31 11:47:09 -070023 test1()
24 test1WithClosures()
25 test2()
26 test3()
Alan Donovan3ddf5a62013-09-18 14:44:57 -040027 if !interp {
Alan Donovanaa5aaab2013-02-21 12:48:38 -050028 test4()
Alan Donovanaa5aaab2013-02-21 12:48:38 -050029 }
Alan Donovan3ddf5a62013-09-18 14:44:57 -040030 test5()
Russ Coxb6ad0742010-03-31 11:47:09 -070031 test6()
32 test6WithClosures()
33 test7()
Russ Cox7276c022013-09-12 14:00:16 -040034 test8()
35 test9()
Alan Donovan3ddf5a62013-09-18 14:44:57 -040036 if !interp {
37 test9reflect1()
38 test9reflect2()
39 }
Russ Cox7276c022013-09-12 14:00:16 -040040 test10()
Alan Donovan3ddf5a62013-09-18 14:44:57 -040041 if !interp {
42 test10reflect1()
43 test10reflect2()
44 }
Russ Cox7276c022013-09-12 14:00:16 -040045 test11()
Alan Donovan3ddf5a62013-09-18 14:44:57 -040046 if !interp {
47 test11reflect1()
48 test11reflect2()
49 }
Russ Cox84736952014-09-06 13:19:08 -040050 test111()
Russ Cox7276c022013-09-12 14:00:16 -040051 test12()
Alan Donovan3ddf5a62013-09-18 14:44:57 -040052 if !interp {
53 test12reflect1()
54 test12reflect2()
55 }
Russ Cox7276c022013-09-12 14:00:16 -040056 test13()
Alan Donovan3ddf5a62013-09-18 14:44:57 -040057 if !interp {
58 test13reflect1()
59 test13reflect2()
60 }
Russ Cox7276c022013-09-12 14:00:16 -040061 test14()
Alan Donovan3ddf5a62013-09-18 14:44:57 -040062 if !interp {
63 test14reflect1()
64 test14reflect2()
65 test15()
66 }
Russ Coxb6ad0742010-03-31 11:47:09 -070067}
68
69func die() {
Russ Coxf75d0d22010-04-01 22:31:27 -070070 runtime.Breakpoint() // can't depend on panic
Russ Coxb6ad0742010-03-31 11:47:09 -070071}
72
Russ Cox7276c022013-09-12 14:00:16 -040073func mustRecoverBody(v1, v2, v3, x interface{}) {
74 v := v1
75 if v != nil {
76 println("spurious recover", v)
77 die()
78 }
79 v = v2
Russ Coxb6ad0742010-03-31 11:47:09 -070080 if v == nil {
Russ Cox84736952014-09-06 13:19:08 -040081 println("missing recover", x.(int))
Russ Coxf75d0d22010-04-01 22:31:27 -070082 die() // panic is useless here
Russ Coxb6ad0742010-03-31 11:47:09 -070083 }
84 if v != x {
85 println("wrong value", v, x)
86 die()
87 }
Russ Coxf75d0d22010-04-01 22:31:27 -070088
Russ Coxb6ad0742010-03-31 11:47:09 -070089 // the value should be gone now regardless
Russ Cox7276c022013-09-12 14:00:16 -040090 v = v3
Russ Coxb6ad0742010-03-31 11:47:09 -070091 if v != nil {
92 println("recover didn't recover")
93 die()
94 }
95}
96
Russ Cox7276c022013-09-12 14:00:16 -040097func doubleRecover() interface{} {
98 return recover()
99}
100
101func mustRecover(x interface{}) {
102 mustRecoverBody(doubleRecover(), recover(), recover(), x)
103}
104
Russ Coxb6ad0742010-03-31 11:47:09 -0700105func mustNotRecover() {
106 v := recover()
107 if v != nil {
Russ Coxf75d0d22010-04-01 22:31:27 -0700108 println("spurious recover", v)
Russ Coxb6ad0742010-03-31 11:47:09 -0700109 die()
110 }
111}
112
113func withoutRecover() {
Russ Coxf75d0d22010-04-01 22:31:27 -0700114 mustNotRecover() // because it's a sub-call
Russ Coxb6ad0742010-03-31 11:47:09 -0700115}
116
117func test1() {
Russ Coxf75d0d22010-04-01 22:31:27 -0700118 defer mustNotRecover() // because mustRecover will squelch it
119 defer mustRecover(1) // because of panic below
120 defer withoutRecover() // should be no-op, leaving for mustRecover to find
Russ Coxb6ad0742010-03-31 11:47:09 -0700121 panic(1)
122}
123
124// Repeat test1 with closures instead of standard function.
125// Interesting because recover bases its decision
126// on the frame pointer of its caller, and a closure's
127// frame pointer is in the middle of its actual arguments
128// (after the hidden ones for the closed-over variables).
129func test1WithClosures() {
130 defer func() {
131 v := recover()
132 if v != nil {
133 println("spurious recover in closure")
134 die()
135 }
136 }()
137 defer func(x interface{}) {
138 mustNotRecover()
139 v := recover()
140 if v == nil {
Russ Cox84736952014-09-06 13:19:08 -0400141 println("missing recover", x.(int))
Russ Coxb6ad0742010-03-31 11:47:09 -0700142 die()
143 }
144 if v != x {
145 println("wrong value", v, x)
146 die()
147 }
148 }(1)
149 defer func() {
150 mustNotRecover()
151 }()
152 panic(1)
153}
154
155func test2() {
156 // Recover only sees the panic argument
157 // if it is called from a deferred call.
158 // It does not see the panic when called from a call within a deferred call (too late)
159 // nor does it see the panic when it *is* the deferred call (too early).
160 defer mustRecover(2)
Russ Coxf75d0d22010-04-01 22:31:27 -0700161 defer recover() // should be no-op
Russ Coxb6ad0742010-03-31 11:47:09 -0700162 panic(2)
163}
164
165func test3() {
166 defer mustNotRecover()
167 defer func() {
Russ Coxf75d0d22010-04-01 22:31:27 -0700168 recover() // should squelch
Russ Coxb6ad0742010-03-31 11:47:09 -0700169 }()
170 panic(3)
171}
172
173func test4() {
174 // Equivalent to test3 but using defer to make the call.
175 defer mustNotRecover()
176 defer func() {
Russ Coxf75d0d22010-04-01 22:31:27 -0700177 defer recover() // should squelch
Russ Coxb6ad0742010-03-31 11:47:09 -0700178 }()
179 panic(4)
180}
181
182// Check that closures can set output arguments.
183// Run g(). If it panics, return x; else return deflt.
184func try(g func(), deflt interface{}) (x interface{}) {
185 defer func() {
186 if v := recover(); v != nil {
187 x = v
188 }
189 }()
190 defer g()
191 return deflt
192}
193
194// Check that closures can set output arguments.
195// Run g(). If it panics, return x; else return deflt.
196func try1(g func(), deflt interface{}) (x interface{}) {
197 defer func() {
198 if v := recover(); v != nil {
199 x = v
200 }
201 }()
202 defer g()
203 x = deflt
204 return
205}
206
207func test5() {
208 v := try(func() { panic(5) }, 55).(int)
209 if v != 5 {
210 println("wrong value", v, 5)
211 die()
212 }
Russ Coxf75d0d22010-04-01 22:31:27 -0700213
214 s := try(func() {}, "hi").(string)
Russ Coxb6ad0742010-03-31 11:47:09 -0700215 if s != "hi" {
216 println("wrong value", s, "hi")
217 die()
218 }
219
220 v = try1(func() { panic(5) }, 55).(int)
221 if v != 5 {
222 println("try1 wrong value", v, 5)
223 die()
224 }
Russ Coxf75d0d22010-04-01 22:31:27 -0700225
226 s = try1(func() {}, "hi").(string)
Russ Coxb6ad0742010-03-31 11:47:09 -0700227 if s != "hi" {
228 println("try1 wrong value", s, "hi")
229 die()
230 }
231}
232
233// When a deferred big call starts, it must first
234// create yet another stack segment to hold the
235// giant frame for x. Make sure that doesn't
236// confuse recover.
237func big(mustRecover bool) {
238 var x [100000]int
239 x[0] = 1
240 x[99999] = 1
241 _ = x
Russ Coxf75d0d22010-04-01 22:31:27 -0700242
Russ Coxb6ad0742010-03-31 11:47:09 -0700243 v := recover()
244 if mustRecover {
245 if v == nil {
246 println("missing big recover")
247 die()
248 }
249 } else {
250 if v != nil {
251 println("spurious big recover")
252 die()
253 }
254 }
255}
256
257func test6() {
258 defer big(false)
259 defer big(true)
260 panic(6)
261}
262
263func test6WithClosures() {
264 defer func() {
265 var x [100000]int
266 x[0] = 1
267 x[99999] = 1
268 _ = x
269 if recover() != nil {
270 println("spurious big closure recover")
271 die()
272 }
273 }()
274 defer func() {
275 var x [100000]int
276 x[0] = 1
277 x[99999] = 1
278 _ = x
279 if recover() == nil {
280 println("missing big closure recover")
281 die()
282 }
283 }()
284 panic("6WithClosures")
285}
286
287func test7() {
288 ok := false
289 func() {
290 // should panic, then call mustRecover 7, which stops the panic.
291 // then should keep processing ordinary defers earlier than that one
292 // before returning.
293 // this test checks that the defer func on the next line actually runs.
294 defer func() { ok = true }()
295 defer mustRecover(7)
296 panic(7)
297 }()
298 if !ok {
299 println("did not run ok func")
300 die()
301 }
302}
Ian Lance Taylorb14a6642012-03-01 08:24:03 -0800303
304func varargs(s *int, a ...int) {
305 *s = 0
306 for _, v := range a {
307 *s += v
308 }
309 if recover() != nil {
310 *s += 100
311 }
312}
313
314func test8a() (r int) {
315 defer varargs(&r, 1, 2, 3)
316 panic(0)
317}
318
319func test8b() (r int) {
320 defer varargs(&r, 4, 5, 6)
321 return
322}
323
324func test8() {
325 if test8a() != 106 || test8b() != 15 {
326 println("wrong value")
327 die()
328 }
329}
Russ Cox7276c022013-09-12 14:00:16 -0400330
Alan Donovan3ddf5a62013-09-18 14:44:57 -0400331type I interface {
332 M()
333}
Russ Cox7276c022013-09-12 14:00:16 -0400334
335// pointer receiver, so no wrapper in i.M()
Alan Donovan3ddf5a62013-09-18 14:44:57 -0400336type T1 struct{}
Russ Cox7276c022013-09-12 14:00:16 -0400337
338func (*T1) M() {
339 mustRecoverBody(doubleRecover(), recover(), recover(), 9)
340}
341
342func test9() {
343 var i I = &T1{}
344 defer i.M()
345 panic(9)
346}
347
348func test9reflect1() {
349 f := reflect.ValueOf(&T1{}).Method(0).Interface().(func())
350 defer f()
351 panic(9)
352}
353
354func test9reflect2() {
355 f := reflect.TypeOf(&T1{}).Method(0).Func.Interface().(func(*T1))
356 defer f(&T1{})
357 panic(9)
358}
359
360// word-sized value receiver, so no wrapper in i.M()
361type T2 uintptr
362
363func (T2) M() {
364 mustRecoverBody(doubleRecover(), recover(), recover(), 10)
365}
366
367func test10() {
368 var i I = T2(0)
369 defer i.M()
370 panic(10)
371}
372
373func test10reflect1() {
374 f := reflect.ValueOf(T2(0)).Method(0).Interface().(func())
375 defer f()
376 panic(10)
377}
378
379func test10reflect2() {
380 f := reflect.TypeOf(T2(0)).Method(0).Func.Interface().(func(T2))
381 defer f(T2(0))
382 panic(10)
383}
384
385// tiny receiver, so basic wrapper in i.M()
Alan Donovan3ddf5a62013-09-18 14:44:57 -0400386type T3 struct{}
Russ Cox7276c022013-09-12 14:00:16 -0400387
388func (T3) M() {
389 mustRecoverBody(doubleRecover(), recover(), recover(), 11)
390}
391
392func test11() {
393 var i I = T3{}
394 defer i.M()
395 panic(11)
396}
397
398func test11reflect1() {
399 f := reflect.ValueOf(T3{}).Method(0).Interface().(func())
400 defer f()
401 panic(11)
402}
403
404func test11reflect2() {
405 f := reflect.TypeOf(T3{}).Method(0).Func.Interface().(func(T3))
406 defer f(T3{})
407 panic(11)
408}
409
Russ Cox84736952014-09-06 13:19:08 -0400410// tiny receiver, so basic wrapper in i.M()
411type T3deeper struct{}
412
413func (T3deeper) M() {
414 badstate() // difference from T3
415 mustRecoverBody(doubleRecover(), recover(), recover(), 111)
416}
417
418func test111() {
419 var i I = T3deeper{}
420 defer i.M()
421 panic(111)
422}
423
424type Tiny struct{}
425
426func (Tiny) M() {
427 panic(112)
428}
429
430// i.M is a wrapper, and i.M panics.
431//
432// This is a torture test for an old implementation of recover that
433// tried to deal with wrapper functions by doing some argument
434// positioning math on both entry and exit. Doing anything on exit
435// is a problem because sometimes functions exit via panic instead
436// of an ordinary return, so panic would have to know to do the
437// same math when unwinding the stack. It gets complicated fast.
438// This particular test never worked with the old scheme, because
439// panic never did the right unwinding math.
440//
441// The new scheme adjusts Panic.argp on entry to a wrapper.
442// It has no exit work, so if a wrapper is interrupted by a panic,
443// there's no cleanup that panic itself must do.
444// This test just works now.
445func badstate() {
446 defer func() {
447 recover()
448 }()
449 var i I = Tiny{}
450 i.M()
451}
452
Russ Cox7276c022013-09-12 14:00:16 -0400453// large receiver, so basic wrapper in i.M()
454type T4 [2]string
455
456func (T4) M() {
457 mustRecoverBody(doubleRecover(), recover(), recover(), 12)
458}
459
460func test12() {
461 var i I = T4{}
462 defer i.M()
463 panic(12)
464}
465
466func test12reflect1() {
467 f := reflect.ValueOf(T4{}).Method(0).Interface().(func())
468 defer f()
469 panic(12)
470}
471
472func test12reflect2() {
473 f := reflect.TypeOf(T4{}).Method(0).Func.Interface().(func(T4))
474 defer f(T4{})
475 panic(12)
476}
477
478// enormous receiver, so wrapper splits stack to call M
479type T5 [8192]byte
480
481func (T5) M() {
482 mustRecoverBody(doubleRecover(), recover(), recover(), 13)
483}
484
485func test13() {
486 var i I = T5{}
487 defer i.M()
488 panic(13)
489}
490
491func test13reflect1() {
492 f := reflect.ValueOf(T5{}).Method(0).Interface().(func())
493 defer f()
494 panic(13)
495}
496
497func test13reflect2() {
498 f := reflect.TypeOf(T5{}).Method(0).Func.Interface().(func(T5))
499 defer f(T5{})
500 panic(13)
501}
502
503// enormous receiver + enormous method frame, so wrapper splits stack to call M,
504// and then M splits stack to allocate its frame.
505// recover must look back two frames to find the panic.
506type T6 [8192]byte
507
508var global byte
509
510func (T6) M() {
511 var x [8192]byte
512 x[0] = 1
513 x[1] = 2
514 for i := range x {
515 global += x[i]
516 }
517 mustRecoverBody(doubleRecover(), recover(), recover(), 14)
518}
519
520func test14() {
521 var i I = T6{}
522 defer i.M()
523 panic(14)
524}
525
526func test14reflect1() {
527 f := reflect.ValueOf(T6{}).Method(0).Interface().(func())
528 defer f()
529 panic(14)
530}
531
532func test14reflect2() {
533 f := reflect.TypeOf(T6{}).Method(0).Func.Interface().(func(T6))
534 defer f(T6{})
535 panic(14)
536}
537
538// function created by reflect.MakeFunc
539
540func reflectFunc(args []reflect.Value) (results []reflect.Value) {
541 mustRecoverBody(doubleRecover(), recover(), recover(), 15)
542 return nil
543}
544
545func test15() {
546 f := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc).Interface().(func())
547 defer f()
548 panic(15)
549}