mirror of
				https://github.com/golang/go.git
				synced 2025-10-31 16:50:58 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			246 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			246 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // $G $D/$F.go && $L $F.$A && ./$A.out
 | |
| 
 | |
| // Copyright 2010 The Go Authors.  All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| // Test of basic recover functionality.
 | |
| 
 | |
| package main
 | |
| 
 | |
| import "runtime"
 | |
| 
 | |
| func main() {
 | |
| 	test1()
 | |
| 	test1WithClosures()
 | |
| 	test2()
 | |
| 	test3()
 | |
| 	test4()
 | |
| 	test5()
 | |
| 	test6()
 | |
| 	test6WithClosures()
 | |
| 	test7()
 | |
| }
 | |
| 
 | |
| func die() {
 | |
| 	runtime.Breakpoint() // can't depend on panic
 | |
| }
 | |
| 
 | |
| func mustRecover(x interface{}) {
 | |
| 	mustNotRecover() // because it's not a defer call
 | |
| 	v := recover()
 | |
| 	if v == nil {
 | |
| 		println("missing recover")
 | |
| 		die() // panic is useless here
 | |
| 	}
 | |
| 	if v != x {
 | |
| 		println("wrong value", v, x)
 | |
| 		die()
 | |
| 	}
 | |
| 
 | |
| 	// the value should be gone now regardless
 | |
| 	v = recover()
 | |
| 	if v != nil {
 | |
| 		println("recover didn't recover")
 | |
| 		die()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func mustNotRecover() {
 | |
| 	v := recover()
 | |
| 	if v != nil {
 | |
| 		println("spurious recover", v)
 | |
| 		die()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func withoutRecover() {
 | |
| 	mustNotRecover() // because it's a sub-call
 | |
| }
 | |
| 
 | |
| func test1() {
 | |
| 	defer mustNotRecover() // because mustRecover will squelch it
 | |
| 	defer mustRecover(1)   // because of panic below
 | |
| 	defer withoutRecover() // should be no-op, leaving for mustRecover to find
 | |
| 	panic(1)
 | |
| }
 | |
| 
 | |
| // Repeat test1 with closures instead of standard function.
 | |
| // Interesting because recover bases its decision
 | |
| // on the frame pointer of its caller, and a closure's
 | |
| // frame pointer is in the middle of its actual arguments
 | |
| // (after the hidden ones for the closed-over variables).
 | |
| func test1WithClosures() {
 | |
| 	defer func() {
 | |
| 		v := recover()
 | |
| 		if v != nil {
 | |
| 			println("spurious recover in closure")
 | |
| 			die()
 | |
| 		}
 | |
| 	}()
 | |
| 	defer func(x interface{}) {
 | |
| 		mustNotRecover()
 | |
| 		v := recover()
 | |
| 		if v == nil {
 | |
| 			println("missing recover")
 | |
| 			die()
 | |
| 		}
 | |
| 		if v != x {
 | |
| 			println("wrong value", v, x)
 | |
| 			die()
 | |
| 		}
 | |
| 	}(1)
 | |
| 	defer func() {
 | |
| 		mustNotRecover()
 | |
| 	}()
 | |
| 	panic(1)
 | |
| }
 | |
| 
 | |
| func test2() {
 | |
| 	// Recover only sees the panic argument
 | |
| 	// if it is called from a deferred call.
 | |
| 	// It does not see the panic when called from a call within a deferred call (too late)
 | |
| 	// nor does it see the panic when it *is* the deferred call (too early).
 | |
| 	defer mustRecover(2)
 | |
| 	defer recover() // should be no-op
 | |
| 	panic(2)
 | |
| }
 | |
| 
 | |
| func test3() {
 | |
| 	defer mustNotRecover()
 | |
| 	defer func() {
 | |
| 		recover() // should squelch
 | |
| 	}()
 | |
| 	panic(3)
 | |
| }
 | |
| 
 | |
| func test4() {
 | |
| 	// Equivalent to test3 but using defer to make the call.
 | |
| 	defer mustNotRecover()
 | |
| 	defer func() {
 | |
| 		defer recover() // should squelch
 | |
| 	}()
 | |
| 	panic(4)
 | |
| }
 | |
| 
 | |
| // Check that closures can set output arguments.
 | |
| // Run g().  If it panics, return x; else return deflt.
 | |
| func try(g func(), deflt interface{}) (x interface{}) {
 | |
| 	defer func() {
 | |
| 		if v := recover(); v != nil {
 | |
| 			x = v
 | |
| 		}
 | |
| 	}()
 | |
| 	defer g()
 | |
| 	return deflt
 | |
| }
 | |
| 
 | |
| // Check that closures can set output arguments.
 | |
| // Run g().  If it panics, return x; else return deflt.
 | |
| func try1(g func(), deflt interface{}) (x interface{}) {
 | |
| 	defer func() {
 | |
| 		if v := recover(); v != nil {
 | |
| 			x = v
 | |
| 		}
 | |
| 	}()
 | |
| 	defer g()
 | |
| 	x = deflt
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func test5() {
 | |
| 	v := try(func() { panic(5) }, 55).(int)
 | |
| 	if v != 5 {
 | |
| 		println("wrong value", v, 5)
 | |
| 		die()
 | |
| 	}
 | |
| 
 | |
| 	s := try(func() {}, "hi").(string)
 | |
| 	if s != "hi" {
 | |
| 		println("wrong value", s, "hi")
 | |
| 		die()
 | |
| 	}
 | |
| 
 | |
| 	v = try1(func() { panic(5) }, 55).(int)
 | |
| 	if v != 5 {
 | |
| 		println("try1 wrong value", v, 5)
 | |
| 		die()
 | |
| 	}
 | |
| 
 | |
| 	s = try1(func() {}, "hi").(string)
 | |
| 	if s != "hi" {
 | |
| 		println("try1 wrong value", s, "hi")
 | |
| 		die()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // When a deferred big call starts, it must first
 | |
| // create yet another stack segment to hold the
 | |
| // giant frame for x.  Make sure that doesn't
 | |
| // confuse recover.
 | |
| func big(mustRecover bool) {
 | |
| 	var x [100000]int
 | |
| 	x[0] = 1
 | |
| 	x[99999] = 1
 | |
| 	_ = x
 | |
| 
 | |
| 	v := recover()
 | |
| 	if mustRecover {
 | |
| 		if v == nil {
 | |
| 			println("missing big recover")
 | |
| 			die()
 | |
| 		}
 | |
| 	} else {
 | |
| 		if v != nil {
 | |
| 			println("spurious big recover")
 | |
| 			die()
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func test6() {
 | |
| 	defer big(false)
 | |
| 	defer big(true)
 | |
| 	panic(6)
 | |
| }
 | |
| 
 | |
| func test6WithClosures() {
 | |
| 	defer func() {
 | |
| 		var x [100000]int
 | |
| 		x[0] = 1
 | |
| 		x[99999] = 1
 | |
| 		_ = x
 | |
| 		if recover() != nil {
 | |
| 			println("spurious big closure recover")
 | |
| 			die()
 | |
| 		}
 | |
| 	}()
 | |
| 	defer func() {
 | |
| 		var x [100000]int
 | |
| 		x[0] = 1
 | |
| 		x[99999] = 1
 | |
| 		_ = x
 | |
| 		if recover() == nil {
 | |
| 			println("missing big closure recover")
 | |
| 			die()
 | |
| 		}
 | |
| 	}()
 | |
| 	panic("6WithClosures")
 | |
| }
 | |
| 
 | |
| func test7() {
 | |
| 	ok := false
 | |
| 	func() {
 | |
| 		// should panic, then call mustRecover 7, which stops the panic.
 | |
| 		// then should keep processing ordinary defers earlier than that one
 | |
| 		// before returning.
 | |
| 		// this test checks that the defer func on the next line actually runs.
 | |
| 		defer func() { ok = true }()
 | |
| 		defer mustRecover(7)
 | |
| 		panic(7)
 | |
| 	}()
 | |
| 	if !ok {
 | |
| 		println("did not run ok func")
 | |
| 		die()
 | |
| 	}
 | |
| }
 | 
