]> Cypherpunks.ru repositories - gostls13.git/blob - test/recover.go
test: disable failing tests under ssa/interp.
[gostls13.git] / test / recover.go
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
9 package main
10
11 import (
12         "os"
13         "reflect"
14         "runtime"
15 )
16
17 func 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
68 func die() {
69         runtime.Breakpoint() // can't depend on panic
70 }
71
72 func 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
96 func doubleRecover() interface{} {
97         return recover()
98 }
99
100 func mustRecover(x interface{}) {
101         mustRecoverBody(doubleRecover(), recover(), recover(), x)
102 }
103
104 func mustNotRecover() {
105         v := recover()
106         if v != nil {
107                 println("spurious recover", v)
108                 die()
109         }
110 }
111
112 func withoutRecover() {
113         mustNotRecover() // because it's a sub-call
114 }
115
116 func 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).
128 func 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
154 func 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
164 func test3() {
165         defer mustNotRecover()
166         defer func() {
167                 recover() // should squelch
168         }()
169         panic(3)
170 }
171
172 func 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.
183 func 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.
195 func 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
206 func 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.
236 func 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
256 func test6() {
257         defer big(false)
258         defer big(true)
259         panic(6)
260 }
261
262 func 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
286 func 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
303 func 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
313 func test8a() (r int) {
314         defer varargs(&r, 1, 2, 3)
315         panic(0)
316 }
317
318 func test8b() (r int) {
319         defer varargs(&r, 4, 5, 6)
320         return
321 }
322
323 func test8() {
324         if test8a() != 106 || test8b() != 15 {
325                 println("wrong value")
326                 die()
327         }
328 }
329
330 type I interface {
331         M()
332 }
333
334 // pointer receiver, so no wrapper in i.M()
335 type T1 struct{}
336
337 func (*T1) M() {
338         mustRecoverBody(doubleRecover(), recover(), recover(), 9)
339 }
340
341 func test9() {
342         var i I = &T1{}
343         defer i.M()
344         panic(9)
345 }
346
347 func test9reflect1() {
348         f := reflect.ValueOf(&T1{}).Method(0).Interface().(func())
349         defer f()
350         panic(9)
351 }
352
353 func 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()
360 type T2 uintptr
361
362 func (T2) M() {
363         mustRecoverBody(doubleRecover(), recover(), recover(), 10)
364 }
365
366 func test10() {
367         var i I = T2(0)
368         defer i.M()
369         panic(10)
370 }
371
372 func test10reflect1() {
373         f := reflect.ValueOf(T2(0)).Method(0).Interface().(func())
374         defer f()
375         panic(10)
376 }
377
378 func 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()
385 type T3 struct{}
386
387 func (T3) M() {
388         mustRecoverBody(doubleRecover(), recover(), recover(), 11)
389 }
390
391 func test11() {
392         var i I = T3{}
393         defer i.M()
394         panic(11)
395 }
396
397 func test11reflect1() {
398         f := reflect.ValueOf(T3{}).Method(0).Interface().(func())
399         defer f()
400         panic(11)
401 }
402
403 func 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()
410 type T4 [2]string
411
412 func (T4) M() {
413         mustRecoverBody(doubleRecover(), recover(), recover(), 12)
414 }
415
416 func test12() {
417         var i I = T4{}
418         defer i.M()
419         panic(12)
420 }
421
422 func test12reflect1() {
423         f := reflect.ValueOf(T4{}).Method(0).Interface().(func())
424         defer f()
425         panic(12)
426 }
427
428 func 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
435 type T5 [8192]byte
436
437 func (T5) M() {
438         mustRecoverBody(doubleRecover(), recover(), recover(), 13)
439 }
440
441 func test13() {
442         var i I = T5{}
443         defer i.M()
444         panic(13)
445 }
446
447 func test13reflect1() {
448         f := reflect.ValueOf(T5{}).Method(0).Interface().(func())
449         defer f()
450         panic(13)
451 }
452
453 func 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.
462 type T6 [8192]byte
463
464 var global byte
465
466 func (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
476 func test14() {
477         var i I = T6{}
478         defer i.M()
479         panic(14)
480 }
481
482 func test14reflect1() {
483         f := reflect.ValueOf(T6{}).Method(0).Interface().(func())
484         defer f()
485         panic(14)
486 }
487
488 func 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
496 func reflectFunc(args []reflect.Value) (results []reflect.Value) {
497         mustRecoverBody(doubleRecover(), recover(), recover(), 15)
498         return nil
499 }
500
501 func test15() {
502         f := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc).Interface().(func())
503         defer f()
504         panic(15)
505 }