modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/test/recover.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 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  }