github.com/goplus/gossa@v0.3.25/testdata/recover2.go (about)

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