blob: f92c15c1d6c9cea42bf5ca1ef95874b75c52d0b0 [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()
Ian Lance Taylor18051c02014-10-22 08:06:15 -070066 test16()
Alan Donovan3ddf5a62013-09-18 14:44:57 -040067 }
Russ Coxb6ad0742010-03-31 11:47:09 -070068}
69
70func die() {
Russ Coxf75d0d22010-04-01 22:31:27 -070071 runtime.Breakpoint() // can't depend on panic
Russ Coxb6ad0742010-03-31 11:47:09 -070072}
73
Russ Cox7276c022013-09-12 14:00:16 -040074func mustRecoverBody(v1, v2, v3, x interface{}) {
75 v := v1
76 if v != nil {
77 println("spurious recover", v)
78 die()
79 }
80 v = v2
Russ Coxb6ad0742010-03-31 11:47:09 -070081 if v == nil {
Russ Cox84736952014-09-06 13:19:08 -040082 println("missing recover", x.(int))
Russ Coxf75d0d22010-04-01 22:31:27 -070083 die() // panic is useless here
Russ Coxb6ad0742010-03-31 11:47:09 -070084 }
85 if v != x {
86 println("wrong value", v, x)
87 die()
88 }
Russ Coxf75d0d22010-04-01 22:31:27 -070089
Russ Coxb6ad0742010-03-31 11:47:09 -070090 // the value should be gone now regardless
Russ Cox7276c022013-09-12 14:00:16 -040091 v = v3
Russ Coxb6ad0742010-03-31 11:47:09 -070092 if v != nil {
93 println("recover didn't recover")
94 die()
95 }
96}
97
Russ Cox7276c022013-09-12 14:00:16 -040098func doubleRecover() interface{} {
99 return recover()
100}
101
102func mustRecover(x interface{}) {
103 mustRecoverBody(doubleRecover(), recover(), recover(), x)
104}
105
Russ Coxb6ad0742010-03-31 11:47:09 -0700106func mustNotRecover() {
107 v := recover()
108 if v != nil {
Russ Coxf75d0d22010-04-01 22:31:27 -0700109 println("spurious recover", v)
Russ Coxb6ad0742010-03-31 11:47:09 -0700110 die()
111 }
112}
113
114func withoutRecover() {
Russ Coxf75d0d22010-04-01 22:31:27 -0700115 mustNotRecover() // because it's a sub-call
Russ Coxb6ad0742010-03-31 11:47:09 -0700116}
117
Ian Lance Taylor18051c02014-10-22 08:06:15 -0700118func withoutRecoverRecursive(n int) {
119 if n == 0 {
120 withoutRecoverRecursive(1)
121 } else {
122 v := recover()
123 if v != nil {
124 println("spurious recover (recursive)", v)
125 die()
126 }
127 }
128}
129
Russ Coxb6ad0742010-03-31 11:47:09 -0700130func test1() {
Ian Lance Taylor18051c02014-10-22 08:06:15 -0700131 defer mustNotRecover() // because mustRecover will squelch it
132 defer mustRecover(1) // because of panic below
133 defer withoutRecover() // should be no-op, leaving for mustRecover to find
134 defer withoutRecoverRecursive(0) // ditto
Russ Coxb6ad0742010-03-31 11:47:09 -0700135 panic(1)
136}
137
138// Repeat test1 with closures instead of standard function.
139// Interesting because recover bases its decision
140// on the frame pointer of its caller, and a closure's
141// frame pointer is in the middle of its actual arguments
142// (after the hidden ones for the closed-over variables).
143func test1WithClosures() {
144 defer func() {
145 v := recover()
146 if v != nil {
147 println("spurious recover in closure")
148 die()
149 }
150 }()
151 defer func(x interface{}) {
152 mustNotRecover()
153 v := recover()
154 if v == nil {
Russ Cox84736952014-09-06 13:19:08 -0400155 println("missing recover", x.(int))
Russ Coxb6ad0742010-03-31 11:47:09 -0700156 die()
157 }
158 if v != x {
159 println("wrong value", v, x)
160 die()
161 }
162 }(1)
163 defer func() {
164 mustNotRecover()
165 }()
166 panic(1)
167}
168
169func test2() {
170 // Recover only sees the panic argument
171 // if it is called from a deferred call.
172 // It does not see the panic when called from a call within a deferred call (too late)
173 // nor does it see the panic when it *is* the deferred call (too early).
174 defer mustRecover(2)
Russ Coxf75d0d22010-04-01 22:31:27 -0700175 defer recover() // should be no-op
Russ Coxb6ad0742010-03-31 11:47:09 -0700176 panic(2)
177}
178
179func test3() {
180 defer mustNotRecover()
181 defer func() {
Russ Coxf75d0d22010-04-01 22:31:27 -0700182 recover() // should squelch
Russ Coxb6ad0742010-03-31 11:47:09 -0700183 }()
184 panic(3)
185}
186
187func test4() {
188 // Equivalent to test3 but using defer to make the call.
189 defer mustNotRecover()
190 defer func() {
Russ Coxf75d0d22010-04-01 22:31:27 -0700191 defer recover() // should squelch
Russ Coxb6ad0742010-03-31 11:47:09 -0700192 }()
193 panic(4)
194}
195
196// Check that closures can set output arguments.
197// Run g(). If it panics, return x; else return deflt.
198func try(g func(), deflt interface{}) (x interface{}) {
199 defer func() {
200 if v := recover(); v != nil {
201 x = v
202 }
203 }()
204 defer g()
205 return deflt
206}
207
208// Check that closures can set output arguments.
209// Run g(). If it panics, return x; else return deflt.
210func try1(g func(), deflt interface{}) (x interface{}) {
211 defer func() {
212 if v := recover(); v != nil {
213 x = v
214 }
215 }()
216 defer g()
217 x = deflt
218 return
219}
220
221func test5() {
222 v := try(func() { panic(5) }, 55).(int)
223 if v != 5 {
224 println("wrong value", v, 5)
225 die()
226 }
Russ Coxf75d0d22010-04-01 22:31:27 -0700227
228 s := try(func() {}, "hi").(string)
Russ Coxb6ad0742010-03-31 11:47:09 -0700229 if s != "hi" {
230 println("wrong value", s, "hi")
231 die()
232 }
233
234 v = try1(func() { panic(5) }, 55).(int)
235 if v != 5 {
236 println("try1 wrong value", v, 5)
237 die()
238 }
Russ Coxf75d0d22010-04-01 22:31:27 -0700239
240 s = try1(func() {}, "hi").(string)
Russ Coxb6ad0742010-03-31 11:47:09 -0700241 if s != "hi" {
242 println("try1 wrong value", s, "hi")
243 die()
244 }
245}
246
247// When a deferred big call starts, it must first
248// create yet another stack segment to hold the
249// giant frame for x. Make sure that doesn't
250// confuse recover.
251func big(mustRecover bool) {
252 var x [100000]int
253 x[0] = 1
254 x[99999] = 1
255 _ = x
Russ Coxf75d0d22010-04-01 22:31:27 -0700256
Russ Coxb6ad0742010-03-31 11:47:09 -0700257 v := recover()
258 if mustRecover {
259 if v == nil {
260 println("missing big recover")
261 die()
262 }
263 } else {
264 if v != nil {
265 println("spurious big recover")
266 die()
267 }
268 }
269}
270
271func test6() {
272 defer big(false)
273 defer big(true)
274 panic(6)
275}
276
277func test6WithClosures() {
278 defer func() {
279 var x [100000]int
280 x[0] = 1
281 x[99999] = 1
282 _ = x
283 if recover() != nil {
284 println("spurious big closure recover")
285 die()
286 }
287 }()
288 defer func() {
289 var x [100000]int
290 x[0] = 1
291 x[99999] = 1
292 _ = x
293 if recover() == nil {
294 println("missing big closure recover")
295 die()
296 }
297 }()
298 panic("6WithClosures")
299}
300
301func test7() {
302 ok := false
303 func() {
304 // should panic, then call mustRecover 7, which stops the panic.
305 // then should keep processing ordinary defers earlier than that one
306 // before returning.
307 // this test checks that the defer func on the next line actually runs.
308 defer func() { ok = true }()
309 defer mustRecover(7)
310 panic(7)
311 }()
312 if !ok {
313 println("did not run ok func")
314 die()
315 }
316}
Ian Lance Taylorb14a6642012-03-01 08:24:03 -0800317
318func varargs(s *int, a ...int) {
319 *s = 0
320 for _, v := range a {
321 *s += v
322 }
323 if recover() != nil {
324 *s += 100
325 }
326}
327
328func test8a() (r int) {
329 defer varargs(&r, 1, 2, 3)
330 panic(0)
331}
332
333func test8b() (r int) {
334 defer varargs(&r, 4, 5, 6)
335 return
336}
337
338func test8() {
339 if test8a() != 106 || test8b() != 15 {
340 println("wrong value")
341 die()
342 }
343}
Russ Cox7276c022013-09-12 14:00:16 -0400344
Alan Donovan3ddf5a62013-09-18 14:44:57 -0400345type I interface {
346 M()
347}
Russ Cox7276c022013-09-12 14:00:16 -0400348
349// pointer receiver, so no wrapper in i.M()
Alan Donovan3ddf5a62013-09-18 14:44:57 -0400350type T1 struct{}
Russ Cox7276c022013-09-12 14:00:16 -0400351
352func (*T1) M() {
353 mustRecoverBody(doubleRecover(), recover(), recover(), 9)
354}
355
356func test9() {
357 var i I = &T1{}
358 defer i.M()
359 panic(9)
360}
361
362func test9reflect1() {
363 f := reflect.ValueOf(&T1{}).Method(0).Interface().(func())
364 defer f()
365 panic(9)
366}
367
368func test9reflect2() {
369 f := reflect.TypeOf(&T1{}).Method(0).Func.Interface().(func(*T1))
370 defer f(&T1{})
371 panic(9)
372}
373
374// word-sized value receiver, so no wrapper in i.M()
375type T2 uintptr
376
377func (T2) M() {
378 mustRecoverBody(doubleRecover(), recover(), recover(), 10)
379}
380
381func test10() {
382 var i I = T2(0)
383 defer i.M()
384 panic(10)
385}
386
387func test10reflect1() {
388 f := reflect.ValueOf(T2(0)).Method(0).Interface().(func())
389 defer f()
390 panic(10)
391}
392
393func test10reflect2() {
394 f := reflect.TypeOf(T2(0)).Method(0).Func.Interface().(func(T2))
395 defer f(T2(0))
396 panic(10)
397}
398
399// tiny receiver, so basic wrapper in i.M()
Alan Donovan3ddf5a62013-09-18 14:44:57 -0400400type T3 struct{}
Russ Cox7276c022013-09-12 14:00:16 -0400401
402func (T3) M() {
403 mustRecoverBody(doubleRecover(), recover(), recover(), 11)
404}
405
406func test11() {
407 var i I = T3{}
408 defer i.M()
409 panic(11)
410}
411
412func test11reflect1() {
413 f := reflect.ValueOf(T3{}).Method(0).Interface().(func())
414 defer f()
415 panic(11)
416}
417
418func test11reflect2() {
419 f := reflect.TypeOf(T3{}).Method(0).Func.Interface().(func(T3))
420 defer f(T3{})
421 panic(11)
422}
423
Russ Cox84736952014-09-06 13:19:08 -0400424// tiny receiver, so basic wrapper in i.M()
425type T3deeper struct{}
426
427func (T3deeper) M() {
428 badstate() // difference from T3
429 mustRecoverBody(doubleRecover(), recover(), recover(), 111)
430}
431
432func test111() {
433 var i I = T3deeper{}
434 defer i.M()
435 panic(111)
436}
437
438type Tiny struct{}
439
440func (Tiny) M() {
441 panic(112)
442}
443
444// i.M is a wrapper, and i.M panics.
445//
446// This is a torture test for an old implementation of recover that
447// tried to deal with wrapper functions by doing some argument
448// positioning math on both entry and exit. Doing anything on exit
449// is a problem because sometimes functions exit via panic instead
450// of an ordinary return, so panic would have to know to do the
451// same math when unwinding the stack. It gets complicated fast.
452// This particular test never worked with the old scheme, because
453// panic never did the right unwinding math.
454//
455// The new scheme adjusts Panic.argp on entry to a wrapper.
456// It has no exit work, so if a wrapper is interrupted by a panic,
457// there's no cleanup that panic itself must do.
458// This test just works now.
459func badstate() {
460 defer func() {
461 recover()
462 }()
463 var i I = Tiny{}
464 i.M()
465}
466
Russ Cox7276c022013-09-12 14:00:16 -0400467// large receiver, so basic wrapper in i.M()
468type T4 [2]string
469
470func (T4) M() {
471 mustRecoverBody(doubleRecover(), recover(), recover(), 12)
472}
473
474func test12() {
475 var i I = T4{}
476 defer i.M()
477 panic(12)
478}
479
480func test12reflect1() {
481 f := reflect.ValueOf(T4{}).Method(0).Interface().(func())
482 defer f()
483 panic(12)
484}
485
486func test12reflect2() {
487 f := reflect.TypeOf(T4{}).Method(0).Func.Interface().(func(T4))
488 defer f(T4{})
489 panic(12)
490}
491
492// enormous receiver, so wrapper splits stack to call M
493type T5 [8192]byte
494
495func (T5) M() {
496 mustRecoverBody(doubleRecover(), recover(), recover(), 13)
497}
498
499func test13() {
500 var i I = T5{}
501 defer i.M()
502 panic(13)
503}
504
505func test13reflect1() {
506 f := reflect.ValueOf(T5{}).Method(0).Interface().(func())
507 defer f()
508 panic(13)
509}
510
511func test13reflect2() {
512 f := reflect.TypeOf(T5{}).Method(0).Func.Interface().(func(T5))
513 defer f(T5{})
514 panic(13)
515}
516
517// enormous receiver + enormous method frame, so wrapper splits stack to call M,
518// and then M splits stack to allocate its frame.
519// recover must look back two frames to find the panic.
520type T6 [8192]byte
521
522var global byte
523
524func (T6) M() {
525 var x [8192]byte
526 x[0] = 1
527 x[1] = 2
528 for i := range x {
529 global += x[i]
530 }
531 mustRecoverBody(doubleRecover(), recover(), recover(), 14)
532}
533
534func test14() {
535 var i I = T6{}
536 defer i.M()
537 panic(14)
538}
539
540func test14reflect1() {
541 f := reflect.ValueOf(T6{}).Method(0).Interface().(func())
542 defer f()
543 panic(14)
544}
545
546func test14reflect2() {
547 f := reflect.TypeOf(T6{}).Method(0).Func.Interface().(func(T6))
548 defer f(T6{})
549 panic(14)
550}
551
552// function created by reflect.MakeFunc
553
554func reflectFunc(args []reflect.Value) (results []reflect.Value) {
555 mustRecoverBody(doubleRecover(), recover(), recover(), 15)
556 return nil
557}
558
559func test15() {
560 f := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc).Interface().(func())
561 defer f()
562 panic(15)
563}
Ian Lance Taylor18051c02014-10-22 08:06:15 -0700564
565func reflectFunc2(args []reflect.Value) (results []reflect.Value) {
566 // This will call reflectFunc3
567 args[0].Interface().(func())()
568 return nil
569}
570
571func reflectFunc3(args []reflect.Value) (results []reflect.Value) {
572 if v := recover(); v != nil {
573 println("spurious recover", v)
574 die()
575 }
576 return nil
577}
578
579func test16() {
580 defer mustRecover(16)
581
582 f2 := reflect.MakeFunc(reflect.TypeOf((func(func()))(nil)), reflectFunc2).Interface().(func(func()))
583 f3 := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc3).Interface().(func())
584 defer f2(f3)
585
586 panic(16)
587}