]> Cypherpunks.ru repositories - gostls13.git/blob - test/recover.go
cmd/compile/internal/inline: score call sites exposed by inlines
[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         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
70 func die() {
71         runtime.Breakpoint() // can't depend on panic
72 }
73
74 func 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
98 func doubleRecover() interface{} {
99         return recover()
100 }
101
102 func mustRecover(x interface{}) {
103         mustRecoverBody(doubleRecover(), recover(), recover(), x)
104 }
105
106 func mustNotRecover() {
107         v := recover()
108         if v != nil {
109                 println("spurious recover", v)
110                 die()
111         }
112 }
113
114 func withoutRecover() {
115         mustNotRecover() // because it's a sub-call
116 }
117
118 func 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
130 func 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).
143 func 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
169 func 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
179 func test3() {
180         defer mustNotRecover()
181         defer func() {
182                 recover() // should squelch
183         }()
184         panic(3)
185 }
186
187 func 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.
198 func 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.
210 func 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
221 func 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.
251 func 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
271 func test6() {
272         defer big(false)
273         defer big(true)
274         panic(6)
275 }
276
277 func 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
301 func 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
318 func 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
328 func test8a() (r int) {
329         defer varargs(&r, 1, 2, 3)
330         panic(0)
331 }
332
333 func test8b() (r int) {
334         defer varargs(&r, 4, 5, 6)
335         return
336 }
337
338 func test8() {
339         if test8a() != 106 || test8b() != 15 {
340                 println("wrong value")
341                 die()
342         }
343 }
344
345 type I interface {
346         M()
347 }
348
349 // pointer receiver, so no wrapper in i.M()
350 type T1 struct{}
351
352 func (*T1) M() {
353         mustRecoverBody(doubleRecover(), recover(), recover(), 9)
354 }
355
356 func test9() {
357         var i I = &T1{}
358         defer i.M()
359         panic(9)
360 }
361
362 func test9reflect1() {
363         f := reflect.ValueOf(&T1{}).Method(0).Interface().(func())
364         defer f()
365         panic(9)
366 }
367
368 func 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()
375 type T2 uintptr
376
377 func (T2) M() {
378         mustRecoverBody(doubleRecover(), recover(), recover(), 10)
379 }
380
381 func test10() {
382         var i I = T2(0)
383         defer i.M()
384         panic(10)
385 }
386
387 func test10reflect1() {
388         f := reflect.ValueOf(T2(0)).Method(0).Interface().(func())
389         defer f()
390         panic(10)
391 }
392
393 func 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()
400 type T3 struct{}
401
402 func (T3) M() {
403         mustRecoverBody(doubleRecover(), recover(), recover(), 11)
404 }
405
406 func test11() {
407         var i I = T3{}
408         defer i.M()
409         panic(11)
410 }
411
412 func test11reflect1() {
413         f := reflect.ValueOf(T3{}).Method(0).Interface().(func())
414         defer f()
415         panic(11)
416 }
417
418 func 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()
425 type T3deeper struct{}
426
427 func (T3deeper) M() {
428         badstate() // difference from T3
429         mustRecoverBody(doubleRecover(), recover(), recover(), 111)
430 }
431
432 func test111() {
433         var i I = T3deeper{}
434         defer i.M()
435         panic(111)
436 }
437
438 type Tiny struct{}
439
440 func (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.
459 func 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()
468 type T4 [2]string
469
470 func (T4) M() {
471         mustRecoverBody(doubleRecover(), recover(), recover(), 12)
472 }
473
474 func test12() {
475         var i I = T4{}
476         defer i.M()
477         panic(12)
478 }
479
480 func test12reflect1() {
481         f := reflect.ValueOf(T4{}).Method(0).Interface().(func())
482         defer f()
483         panic(12)
484 }
485
486 func 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
493 type T5 [8192]byte
494
495 func (T5) M() {
496         mustRecoverBody(doubleRecover(), recover(), recover(), 13)
497 }
498
499 func test13() {
500         var i I = T5{}
501         defer i.M()
502         panic(13)
503 }
504
505 func test13reflect1() {
506         f := reflect.ValueOf(T5{}).Method(0).Interface().(func())
507         defer f()
508         panic(13)
509 }
510
511 func 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.
520 type T6 [8192]byte
521
522 var global byte
523
524 func (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
534 func test14() {
535         var i I = T6{}
536         defer i.M()
537         panic(14)
538 }
539
540 func test14reflect1() {
541         f := reflect.ValueOf(T6{}).Method(0).Interface().(func())
542         defer f()
543         panic(14)
544 }
545
546 func 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
554 func reflectFunc(args []reflect.Value) (results []reflect.Value) {
555         mustRecoverBody(doubleRecover(), recover(), recover(), 15)
556         return nil
557 }
558
559 func test15() {
560         f := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc).Interface().(func())
561         defer f()
562         panic(15)
563 }
564
565 func reflectFunc2(args []reflect.Value) (results []reflect.Value) {
566         // This will call reflectFunc3
567         args[0].Interface().(func())()
568         return nil
569 }
570
571 func 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
579 func 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 }