1// Copyright 2015 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package main 6 7import ( 8 "fmt" 9 "runtime" 10 "runtime/debug" 11 "time" 12) 13 14func init() { 15 registerInit("InitDeadlock", InitDeadlock) 16 registerInit("NoHelperGoroutines", NoHelperGoroutines) 17 18 register("SimpleDeadlock", SimpleDeadlock) 19 register("LockedDeadlock", LockedDeadlock) 20 register("LockedDeadlock2", LockedDeadlock2) 21 register("GoexitDeadlock", GoexitDeadlock) 22 register("StackOverflow", StackOverflow) 23 register("ThreadExhaustion", ThreadExhaustion) 24 register("RecursivePanic", RecursivePanic) 25 register("RecursivePanic2", RecursivePanic2) 26 register("RecursivePanic3", RecursivePanic3) 27 register("RecursivePanic4", RecursivePanic4) 28 register("RecursivePanic5", RecursivePanic5) 29 register("GoexitExit", GoexitExit) 30 register("GoNil", GoNil) 31 register("MainGoroutineID", MainGoroutineID) 32 register("Breakpoint", Breakpoint) 33 register("GoexitInPanic", GoexitInPanic) 34 register("PanicAfterGoexit", PanicAfterGoexit) 35 register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit) 36 register("RecoverBeforePanicAfterGoexit", RecoverBeforePanicAfterGoexit) 37 register("RecoverBeforePanicAfterGoexit2", RecoverBeforePanicAfterGoexit2) 38 register("PanicTraceback", PanicTraceback) 39 register("GoschedInPanic", GoschedInPanic) 40 register("SyscallInPanic", SyscallInPanic) 41 register("PanicLoop", PanicLoop) 42} 43 44func SimpleDeadlock() { 45 select {} 46 panic("not reached") 47} 48 49func InitDeadlock() { 50 select {} 51 panic("not reached") 52} 53 54func LockedDeadlock() { 55 runtime.LockOSThread() 56 select {} 57} 58 59func LockedDeadlock2() { 60 go func() { 61 runtime.LockOSThread() 62 select {} 63 }() 64 time.Sleep(time.Millisecond) 65 select {} 66} 67 68func GoexitDeadlock() { 69 F := func() { 70 for i := 0; i < 10; i++ { 71 } 72 } 73 74 go F() 75 go F() 76 runtime.Goexit() 77} 78 79func StackOverflow() { 80 var f func() byte 81 f = func() byte { 82 var buf [64 << 10]byte 83 return buf[0] + f() 84 } 85 debug.SetMaxStack(1474560) 86 f() 87} 88 89func ThreadExhaustion() { 90 debug.SetMaxThreads(10) 91 c := make(chan int) 92 for i := 0; i < 100; i++ { 93 go func() { 94 runtime.LockOSThread() 95 c <- 0 96 select {} 97 }() 98 <-c 99 } 100} 101 102func RecursivePanic() { 103 func() { 104 defer func() { 105 fmt.Println(recover()) 106 }() 107 var x [8192]byte 108 func(x [8192]byte) { 109 defer func() { 110 if err := recover(); err != nil { 111 panic("wrap: " + err.(string)) 112 } 113 }() 114 panic("bad") 115 }(x) 116 }() 117 panic("again") 118} 119 120// Same as RecursivePanic, but do the first recover and the second panic in 121// separate defers, and make sure they are executed in the correct order. 122func RecursivePanic2() { 123 func() { 124 defer func() { 125 fmt.Println(recover()) 126 }() 127 var x [8192]byte 128 func(x [8192]byte) { 129 defer func() { 130 panic("second panic") 131 }() 132 defer func() { 133 fmt.Println(recover()) 134 }() 135 panic("first panic") 136 }(x) 137 }() 138 panic("third panic") 139} 140 141// Make sure that the first panic finished as a panic, even though the second 142// panic was recovered 143func RecursivePanic3() { 144 defer func() { 145 defer func() { 146 recover() 147 }() 148 panic("second panic") 149 }() 150 panic("first panic") 151} 152 153// Test case where a single defer recovers one panic but starts another panic. If 154// the second panic is never recovered, then the recovered first panic will still 155// appear on the panic stack (labeled '[recovered]') and the runtime stack. 156func RecursivePanic4() { 157 defer func() { 158 recover() 159 panic("second panic") 160 }() 161 panic("first panic") 162} 163 164// Test case where we have an open-coded defer higher up the stack (in two), and 165// in the current function (three) we recover in a defer while we still have 166// another defer to be processed. 167func RecursivePanic5() { 168 one() 169 panic("third panic") 170} 171 172//go:noinline 173func one() { 174 two() 175} 176 177//go:noinline 178func two() { 179 defer func() { 180 }() 181 182 three() 183} 184 185//go:noinline 186func three() { 187 defer func() { 188 }() 189 190 defer func() { 191 fmt.Println(recover()) 192 }() 193 194 defer func() { 195 fmt.Println(recover()) 196 panic("second panic") 197 }() 198 199 panic("first panic") 200} 201 202func GoexitExit() { 203 println("t1") 204 go func() { 205 time.Sleep(time.Millisecond) 206 }() 207 i := 0 208 println("t2") 209 runtime.SetFinalizer(&i, func(p *int) {}) 210 println("t3") 211 runtime.GC() 212 println("t4") 213 runtime.Goexit() 214} 215 216func GoNil() { 217 defer func() { 218 recover() 219 }() 220 var f func() 221 go f() 222 select {} 223} 224 225func MainGoroutineID() { 226 panic("test") 227} 228 229func NoHelperGoroutines() { 230 i := 0 231 runtime.SetFinalizer(&i, func(p *int) {}) 232 time.AfterFunc(time.Hour, func() {}) 233 panic("oops") 234} 235 236func Breakpoint() { 237 runtime.Breakpoint() 238} 239 240func GoexitInPanic() { 241 go func() { 242 defer func() { 243 runtime.Goexit() 244 }() 245 panic("hello") 246 }() 247 runtime.Goexit() 248} 249 250type errorThatGosched struct{} 251 252func (errorThatGosched) Error() string { 253 runtime.Gosched() 254 return "errorThatGosched" 255} 256 257func GoschedInPanic() { 258 panic(errorThatGosched{}) 259} 260 261type errorThatPrint struct{} 262 263func (errorThatPrint) Error() string { 264 fmt.Println("1") 265 fmt.Println("2") 266 return "3" 267} 268 269func SyscallInPanic() { 270 panic(errorThatPrint{}) 271} 272 273func PanicAfterGoexit() { 274 defer func() { 275 panic("hello") 276 }() 277 runtime.Goexit() 278} 279 280func RecoveredPanicAfterGoexit() { 281 defer func() { 282 defer func() { 283 r := recover() 284 if r == nil { 285 panic("bad recover") 286 } 287 }() 288 panic("hello") 289 }() 290 runtime.Goexit() 291} 292 293func RecoverBeforePanicAfterGoexit() { 294 // 1. defer a function that recovers 295 // 2. defer a function that panics 296 // 3. call goexit 297 // Goexit runs the #2 defer. Its panic 298 // is caught by the #1 defer. For Goexit, we explicitly 299 // resume execution in the Goexit loop, instead of resuming 300 // execution in the caller (which would make the Goexit disappear!) 301 defer func() { 302 r := recover() 303 if r == nil { 304 panic("bad recover") 305 } 306 }() 307 defer func() { 308 panic("hello") 309 }() 310 runtime.Goexit() 311} 312 313func RecoverBeforePanicAfterGoexit2() { 314 for i := 0; i < 2; i++ { 315 defer func() { 316 }() 317 } 318 // 1. defer a function that recovers 319 // 2. defer a function that panics 320 // 3. call goexit 321 // Goexit runs the #2 defer. Its panic 322 // is caught by the #1 defer. For Goexit, we explicitly 323 // resume execution in the Goexit loop, instead of resuming 324 // execution in the caller (which would make the Goexit disappear!) 325 defer func() { 326 r := recover() 327 if r == nil { 328 panic("bad recover") 329 } 330 }() 331 defer func() { 332 panic("hello") 333 }() 334 runtime.Goexit() 335} 336 337func PanicTraceback() { 338 pt1() 339} 340 341func pt1() { 342 defer func() { 343 panic("panic pt1") 344 }() 345 pt2() 346} 347 348func pt2() { 349 defer func() { 350 panic("panic pt2") 351 }() 352 panic("hello") 353} 354 355type panicError struct{} 356 357func (*panicError) Error() string { 358 panic("double error") 359} 360 361func PanicLoop() { 362 panic(&panicError{}) 363} 364