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 "runtime" 12 13func main() { 14 test1() 15 test1WithClosures() 16 test2() 17 test3() 18 test4() 19 test5() 20 test6() 21 test6WithClosures() 22 test7() 23} 24 25func die() { 26 runtime.Breakpoint() // can't depend on panic 27} 28 29func mustRecover(x interface{}) { 30 mustNotRecover() // because it's not a defer call 31 v := recover() 32 if v == nil { 33 println("missing recover") 34 die() // panic is useless here 35 } 36 if v != x { 37 println("wrong value", v, x) 38 die() 39 } 40 41 // the value should be gone now regardless 42 v = recover() 43 if v != nil { 44 println("recover didn't recover") 45 die() 46 } 47} 48 49func mustNotRecover() { 50 v := recover() 51 if v != nil { 52 println("spurious recover", v) 53 die() 54 } 55} 56 57func withoutRecover() { 58 mustNotRecover() // because it's a sub-call 59} 60 61func test1() { 62 defer mustNotRecover() // because mustRecover will squelch it 63 defer mustRecover(1) // because of panic below 64 defer withoutRecover() // should be no-op, leaving for mustRecover to find 65 panic(1) 66} 67 68// Repeat test1 with closures instead of standard function. 69// Interesting because recover bases its decision 70// on the frame pointer of its caller, and a closure's 71// frame pointer is in the middle of its actual arguments 72// (after the hidden ones for the closed-over variables). 73func test1WithClosures() { 74 defer func() { 75 v := recover() 76 if v != nil { 77 println("spurious recover in closure") 78 die() 79 } 80 }() 81 defer func(x interface{}) { 82 mustNotRecover() 83 v := recover() 84 if v == nil { 85 println("missing recover") 86 die() 87 } 88 if v != x { 89 println("wrong value", v, x) 90 die() 91 } 92 }(1) 93 defer func() { 94 mustNotRecover() 95 }() 96 panic(1) 97} 98 99func test2() { 100 // Recover only sees the panic argument 101 // if it is called from a deferred call. 102 // It does not see the panic when called from a call within a deferred call (too late) 103 // nor does it see the panic when it *is* the deferred call (too early). 104 defer mustRecover(2) 105 defer recover() // should be no-op 106 panic(2) 107} 108 109func test3() { 110 defer mustNotRecover() 111 defer func() { 112 recover() // should squelch 113 }() 114 panic(3) 115} 116 117func test4() { 118 // Equivalent to test3 but using defer to make the call. 119 defer mustNotRecover() 120 defer func() { 121 defer recover() // should squelch 122 }() 123 panic(4) 124} 125 126// Check that closures can set output arguments. 127// Run g(). If it panics, return x; else return deflt. 128func try(g func(), deflt interface{}) (x interface{}) { 129 defer func() { 130 if v := recover(); v != nil { 131 x = v 132 } 133 }() 134 defer g() 135 return deflt 136} 137 138// Check that closures can set output arguments. 139// Run g(). If it panics, return x; else return deflt. 140func try1(g func(), deflt interface{}) (x interface{}) { 141 defer func() { 142 if v := recover(); v != nil { 143 x = v 144 } 145 }() 146 defer g() 147 x = deflt 148 return 149} 150 151func test5() { 152 v := try(func() { panic(5) }, 55).(int) 153 if v != 5 { 154 println("wrong value", v, 5) 155 die() 156 } 157 158 s := try(func() {}, "hi").(string) 159 if s != "hi" { 160 println("wrong value", s, "hi") 161 die() 162 } 163 164 v = try1(func() { panic(5) }, 55).(int) 165 if v != 5 { 166 println("try1 wrong value", v, 5) 167 die() 168 } 169 170 s = try1(func() {}, "hi").(string) 171 if s != "hi" { 172 println("try1 wrong value", s, "hi") 173 die() 174 } 175} 176 177// When a deferred big call starts, it must first 178// create yet another stack segment to hold the 179// giant frame for x. Make sure that doesn't 180// confuse recover. 181func big(mustRecover bool) { 182 var x [100000]int 183 x[0] = 1 184 x[99999] = 1 185 _ = x 186 187 v := recover() 188 if mustRecover { 189 if v == nil { 190 println("missing big recover") 191 die() 192 } 193 } else { 194 if v != nil { 195 println("spurious big recover") 196 die() 197 } 198 } 199} 200 201func test6() { 202 defer big(false) 203 defer big(true) 204 panic(6) 205} 206 207func test6WithClosures() { 208 defer func() { 209 var x [100000]int 210 x[0] = 1 211 x[99999] = 1 212 _ = x 213 if recover() != nil { 214 println("spurious big closure recover") 215 die() 216 } 217 }() 218 defer func() { 219 var x [100000]int 220 x[0] = 1 221 x[99999] = 1 222 _ = x 223 if recover() == nil { 224 println("missing big closure recover") 225 die() 226 } 227 }() 228 panic("6WithClosures") 229} 230 231func test7() { 232 ok := false 233 func() { 234 // should panic, then call mustRecover 7, which stops the panic. 235 // then should keep processing ordinary defers earlier than that one 236 // before returning. 237 // this test checks that the defer func on the next line actually runs. 238 defer func() { ok = true }() 239 defer mustRecover(7) 240 panic(7) 241 }() 242 if !ok { 243 println("did not run ok func") 244 die() 245 } 246} 247 248func varargs(s *int, a ...int) { 249 *s = 0 250 for _, v := range a { 251 *s += v 252 } 253 if recover() != nil { 254 *s += 100 255 } 256} 257 258func test8a() (r int) { 259 defer varargs(&r, 1, 2, 3) 260 panic(0) 261} 262 263func test8b() (r int) { 264 defer varargs(&r, 4, 5, 6) 265 return 266} 267 268func test8() { 269 if test8a() != 106 || test8b() != 15 { 270 println("wrong value") 271 die() 272 } 273} 274