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	test12()
51	if !interp {
52		test12reflect1()
53		test12reflect2()
54	}
55	test13()
56	if !interp {
57		test13reflect1()
58		test13reflect2()
59	}
60	test14()
61	if !interp {
62		test14reflect1()
63		test14reflect2()
64		test15()
65	}
66}
67
68func die() {
69	runtime.Breakpoint() // can't depend on panic
70}
71
72func mustRecoverBody(v1, v2, v3, x interface{}) {
73	v := v1
74	if v != nil {
75		println("spurious recover", v)
76		die()
77	}
78	v = v2
79	if v == nil {
80		println("missing recover")
81		die() // panic is useless here
82	}
83	if v != x {
84		println("wrong value", v, x)
85		die()
86	}
87
88	// the value should be gone now regardless
89	v = v3
90	if v != nil {
91		println("recover didn't recover")
92		die()
93	}
94}
95
96func doubleRecover() interface{} {
97	return recover()
98}
99
100func mustRecover(x interface{}) {
101	mustRecoverBody(doubleRecover(), recover(), recover(), x)
102}
103
104func mustNotRecover() {
105	v := recover()
106	if v != nil {
107		println("spurious recover", v)
108		die()
109	}
110}
111
112func withoutRecover() {
113	mustNotRecover() // because it's a sub-call
114}
115
116func test1() {
117	defer mustNotRecover() // because mustRecover will squelch it
118	defer mustRecover(1)   // because of panic below
119	defer withoutRecover() // should be no-op, leaving for mustRecover to find
120	panic(1)
121}
122
123// Repeat test1 with closures instead of standard function.
124// Interesting because recover bases its decision
125// on the frame pointer of its caller, and a closure's
126// frame pointer is in the middle of its actual arguments
127// (after the hidden ones for the closed-over variables).
128func test1WithClosures() {
129	defer func() {
130		v := recover()
131		if v != nil {
132			println("spurious recover in closure")
133			die()
134		}
135	}()
136	defer func(x interface{}) {
137		mustNotRecover()
138		v := recover()
139		if v == nil {
140			println("missing recover")
141			die()
142		}
143		if v != x {
144			println("wrong value", v, x)
145			die()
146		}
147	}(1)
148	defer func() {
149		mustNotRecover()
150	}()
151	panic(1)
152}
153
154func test2() {
155	// Recover only sees the panic argument
156	// if it is called from a deferred call.
157	// It does not see the panic when called from a call within a deferred call (too late)
158	// nor does it see the panic when it *is* the deferred call (too early).
159	defer mustRecover(2)
160	defer recover() // should be no-op
161	panic(2)
162}
163
164func test3() {
165	defer mustNotRecover()
166	defer func() {
167		recover() // should squelch
168	}()
169	panic(3)
170}
171
172func test4() {
173	// Equivalent to test3 but using defer to make the call.
174	defer mustNotRecover()
175	defer func() {
176		defer recover() // should squelch
177	}()
178	panic(4)
179}
180
181// Check that closures can set output arguments.
182// Run g().  If it panics, return x; else return deflt.
183func try(g func(), deflt interface{}) (x interface{}) {
184	defer func() {
185		if v := recover(); v != nil {
186			x = v
187		}
188	}()
189	defer g()
190	return deflt
191}
192
193// Check that closures can set output arguments.
194// Run g().  If it panics, return x; else return deflt.
195func try1(g func(), deflt interface{}) (x interface{}) {
196	defer func() {
197		if v := recover(); v != nil {
198			x = v
199		}
200	}()
201	defer g()
202	x = deflt
203	return
204}
205
206func test5() {
207	v := try(func() { panic(5) }, 55).(int)
208	if v != 5 {
209		println("wrong value", v, 5)
210		die()
211	}
212
213	s := try(func() {}, "hi").(string)
214	if s != "hi" {
215		println("wrong value", s, "hi")
216		die()
217	}
218
219	v = try1(func() { panic(5) }, 55).(int)
220	if v != 5 {
221		println("try1 wrong value", v, 5)
222		die()
223	}
224
225	s = try1(func() {}, "hi").(string)
226	if s != "hi" {
227		println("try1 wrong value", s, "hi")
228		die()
229	}
230}
231
232// When a deferred big call starts, it must first
233// create yet another stack segment to hold the
234// giant frame for x.  Make sure that doesn't
235// confuse recover.
236func big(mustRecover bool) {
237	var x [100000]int
238	x[0] = 1
239	x[99999] = 1
240	_ = x
241
242	v := recover()
243	if mustRecover {
244		if v == nil {
245			println("missing big recover")
246			die()
247		}
248	} else {
249		if v != nil {
250			println("spurious big recover")
251			die()
252		}
253	}
254}
255
256func test6() {
257	defer big(false)
258	defer big(true)
259	panic(6)
260}
261
262func test6WithClosures() {
263	defer func() {
264		var x [100000]int
265		x[0] = 1
266		x[99999] = 1
267		_ = x
268		if recover() != nil {
269			println("spurious big closure recover")
270			die()
271		}
272	}()
273	defer func() {
274		var x [100000]int
275		x[0] = 1
276		x[99999] = 1
277		_ = x
278		if recover() == nil {
279			println("missing big closure recover")
280			die()
281		}
282	}()
283	panic("6WithClosures")
284}
285
286func test7() {
287	ok := false
288	func() {
289		// should panic, then call mustRecover 7, which stops the panic.
290		// then should keep processing ordinary defers earlier than that one
291		// before returning.
292		// this test checks that the defer func on the next line actually runs.
293		defer func() { ok = true }()
294		defer mustRecover(7)
295		panic(7)
296	}()
297	if !ok {
298		println("did not run ok func")
299		die()
300	}
301}
302
303func varargs(s *int, a ...int) {
304	*s = 0
305	for _, v := range a {
306		*s += v
307	}
308	if recover() != nil {
309		*s += 100
310	}
311}
312
313func test8a() (r int) {
314	defer varargs(&r, 1, 2, 3)
315	panic(0)
316}
317
318func test8b() (r int) {
319	defer varargs(&r, 4, 5, 6)
320	return
321}
322
323func test8() {
324	if test8a() != 106 || test8b() != 15 {
325		println("wrong value")
326		die()
327	}
328}
329
330type I interface {
331	M()
332}
333
334// pointer receiver, so no wrapper in i.M()
335type T1 struct{}
336
337func (*T1) M() {
338	mustRecoverBody(doubleRecover(), recover(), recover(), 9)
339}
340
341func test9() {
342	var i I = &T1{}
343	defer i.M()
344	panic(9)
345}
346
347func test9reflect1() {
348	f := reflect.ValueOf(&T1{}).Method(0).Interface().(func())
349	defer f()
350	panic(9)
351}
352
353func test9reflect2() {
354	f := reflect.TypeOf(&T1{}).Method(0).Func.Interface().(func(*T1))
355	defer f(&T1{})
356	panic(9)
357}
358
359// word-sized value receiver, so no wrapper in i.M()
360type T2 uintptr
361
362func (T2) M() {
363	mustRecoverBody(doubleRecover(), recover(), recover(), 10)
364}
365
366func test10() {
367	var i I = T2(0)
368	defer i.M()
369	panic(10)
370}
371
372func test10reflect1() {
373	f := reflect.ValueOf(T2(0)).Method(0).Interface().(func())
374	defer f()
375	panic(10)
376}
377
378func test10reflect2() {
379	f := reflect.TypeOf(T2(0)).Method(0).Func.Interface().(func(T2))
380	defer f(T2(0))
381	panic(10)
382}
383
384// tiny receiver, so basic wrapper in i.M()
385type T3 struct{}
386
387func (T3) M() {
388	mustRecoverBody(doubleRecover(), recover(), recover(), 11)
389}
390
391func test11() {
392	var i I = T3{}
393	defer i.M()
394	panic(11)
395}
396
397func test11reflect1() {
398	f := reflect.ValueOf(T3{}).Method(0).Interface().(func())
399	defer f()
400	panic(11)
401}
402
403func test11reflect2() {
404	f := reflect.TypeOf(T3{}).Method(0).Func.Interface().(func(T3))
405	defer f(T3{})
406	panic(11)
407}
408
409// large receiver, so basic wrapper in i.M()
410type T4 [2]string
411
412func (T4) M() {
413	mustRecoverBody(doubleRecover(), recover(), recover(), 12)
414}
415
416func test12() {
417	var i I = T4{}
418	defer i.M()
419	panic(12)
420}
421
422func test12reflect1() {
423	f := reflect.ValueOf(T4{}).Method(0).Interface().(func())
424	defer f()
425	panic(12)
426}
427
428func test12reflect2() {
429	f := reflect.TypeOf(T4{}).Method(0).Func.Interface().(func(T4))
430	defer f(T4{})
431	panic(12)
432}
433
434// enormous receiver, so wrapper splits stack to call M
435type T5 [8192]byte
436
437func (T5) M() {
438	mustRecoverBody(doubleRecover(), recover(), recover(), 13)
439}
440
441func test13() {
442	var i I = T5{}
443	defer i.M()
444	panic(13)
445}
446
447func test13reflect1() {
448	f := reflect.ValueOf(T5{}).Method(0).Interface().(func())
449	defer f()
450	panic(13)
451}
452
453func test13reflect2() {
454	f := reflect.TypeOf(T5{}).Method(0).Func.Interface().(func(T5))
455	defer f(T5{})
456	panic(13)
457}
458
459// enormous receiver + enormous method frame, so wrapper splits stack to call M,
460// and then M splits stack to allocate its frame.
461// recover must look back two frames to find the panic.
462type T6 [8192]byte
463
464var global byte
465
466func (T6) M() {
467	var x [8192]byte
468	x[0] = 1
469	x[1] = 2
470	for i := range x {
471		global += x[i]
472	}
473	mustRecoverBody(doubleRecover(), recover(), recover(), 14)
474}
475
476func test14() {
477	var i I = T6{}
478	defer i.M()
479	panic(14)
480}
481
482func test14reflect1() {
483	f := reflect.ValueOf(T6{}).Method(0).Interface().(func())
484	defer f()
485	panic(14)
486}
487
488func test14reflect2() {
489	f := reflect.TypeOf(T6{}).Method(0).Func.Interface().(func(T6))
490	defer f(T6{})
491	panic(14)
492}
493
494// function created by reflect.MakeFunc
495
496func reflectFunc(args []reflect.Value) (results []reflect.Value) {
497	mustRecoverBody(doubleRecover(), recover(), recover(), 15)
498	return nil
499}
500
501func test15() {
502	f := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc).Interface().(func())
503	defer f()
504	panic(15)
505}
506