1// run
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 (
12	"os"
13	"reflect"
14	"runtime"
15)
16
17func main() {
18	// go.tools/ssa/interp still has:
19	// - some lesser bugs in recover()
20	// - incomplete support for reflection
21	interp := os.Getenv("GOSSAINTERP") != ""
22
23	test1()
24	test1WithClosures()
25	test2()
26	test3()
27	if !interp {
28		test4()
29	}
30	test5()
31	test6()
32	test6WithClosures()
33	test7()
34	test8()
35	test9()
36	if !interp {
37		test9reflect1()
38		test9reflect2()
39	}
40	test10()
41	if !interp {
42		test10reflect1()
43		test10reflect2()
44	}
45	test11()
46	if !interp {
47		test11reflect1()
48		test11reflect2()
49	}
50	test111()
51	test12()
52	if !interp {
53		test12reflect1()
54		test12reflect2()
55	}
56	test13()
57	if !interp {
58		test13reflect1()
59		test13reflect2()
60	}
61	test14()
62	if !interp {
63		test14reflect1()
64		test14reflect2()
65		test15()
66		test16()
67	}
68}
69
70func die() {
71	runtime.Breakpoint() // can't depend on panic
72}
73
74func mustRecoverBody(v1, v2, v3, x interface{}) {
75	v := v1
76	if v != nil {
77		println("spurious recover", v)
78		die()
79	}
80	v = v2
81	if v == nil {
82		println("missing recover", x.(int))
83		die() // panic is useless here
84	}
85	if v != x {
86		println("wrong value", v, x)
87		die()
88	}
89
90	// the value should be gone now regardless
91	v = v3
92	if v != nil {
93		println("recover didn't recover")
94		die()
95	}
96}
97
98func doubleRecover() interface{} {
99	return recover()
100}
101
102func mustRecover(x interface{}) {
103	mustRecoverBody(doubleRecover(), recover(), recover(), x)
104}
105
106func mustNotRecover() {
107	v := recover()
108	if v != nil {
109		println("spurious recover", v)
110		die()
111	}
112}
113
114func withoutRecover() {
115	mustNotRecover() // because it's a sub-call
116}
117
118func 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
130func test1() {
131	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
135	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 {
155			println("missing recover", x.(int))
156			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)
175	defer recover() // should be no-op
176	panic(2)
177}
178
179func test3() {
180	defer mustNotRecover()
181	defer func() {
182		recover() // should squelch
183	}()
184	panic(3)
185}
186
187func test4() {
188	// Equivalent to test3 but using defer to make the call.
189	defer mustNotRecover()
190	defer func() {
191		defer recover() // should squelch
192	}()
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	}
227
228	s := try(func() {}, "hi").(string)
229	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	}
239
240	s = try1(func() {}, "hi").(string)
241	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
256
257	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}
317
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}
344
345type I interface {
346	M()
347}
348
349// pointer receiver, so no wrapper in i.M()
350type T1 struct{}
351
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()
400type T3 struct{}
401
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
424// 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
467// 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}
564
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}
588