| // Copyright 2014 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. |
| |
| package runtime |
| |
| import ( |
| "runtime/internal/atomic" |
| "unsafe" |
| ) |
| |
| // For gccgo, use go:linkname to rename compiler-called functions to |
| // themselves, so that the compiler will export them. |
| // |
| //go:linkname deferproc runtime.deferproc |
| //go:linkname deferreturn runtime.deferreturn |
| //go:linkname setdeferretaddr runtime.setdeferretaddr |
| //go:linkname checkdefer runtime.checkdefer |
| //go:linkname gopanic runtime.gopanic |
| //go:linkname canrecover runtime.canrecover |
| //go:linkname makefuncfficanrecover runtime.makefuncfficanrecover |
| //go:linkname makefuncreturning runtime.makefuncreturning |
| //go:linkname gorecover runtime.gorecover |
| //go:linkname deferredrecover runtime.deferredrecover |
| //go:linkname panicmem runtime.panicmem |
| // Temporary for C code to call: |
| //go:linkname throw runtime.throw |
| |
| // Calling panic with one of the errors below will call errorString.Error |
| // which will call mallocgc to concatenate strings. That will fail if |
| // malloc is locked, causing a confusing error message. Throw a better |
| // error message instead. |
| func panicCheckMalloc(err error) { |
| gp := getg() |
| if gp != nil && gp.m != nil && gp.m.mallocing != 0 { |
| throw(string(err.(errorString))) |
| } |
| } |
| |
| var indexError = error(errorString("index out of range")) |
| |
| // The panicindex, panicslice, and panicdivide functions are called by |
| // code generated by the compiler for out of bounds index expressions, |
| // out of bounds slice expressions, and division by zero. The |
| // panicdivide (again), panicoverflow, panicfloat, and panicmem |
| // functions are called by the signal handler when a signal occurs |
| // indicating the respective problem. |
| // |
| // Since panicindex and panicslice are never called directly, and |
| // since the runtime package should never have an out of bounds slice |
| // or array reference, if we see those functions called from the |
| // runtime package we turn the panic into a throw. That will dump the |
| // entire runtime stack for easier debugging. |
| |
| func panicindex() { |
| name, _, _ := funcfileline(getcallerpc(), -1) |
| if hasprefix(name, "runtime.") { |
| throw(string(indexError.(errorString))) |
| } |
| panicCheckMalloc(indexError) |
| panic(indexError) |
| } |
| |
| var sliceError = error(errorString("slice bounds out of range")) |
| |
| func panicslice() { |
| name, _, _ := funcfileline(getcallerpc(), -1) |
| if hasprefix(name, "runtime.") { |
| throw(string(sliceError.(errorString))) |
| } |
| panicCheckMalloc(sliceError) |
| panic(sliceError) |
| } |
| |
| var divideError = error(errorString("integer divide by zero")) |
| |
| func panicdivide() { |
| panicCheckMalloc(divideError) |
| panic(divideError) |
| } |
| |
| var overflowError = error(errorString("integer overflow")) |
| |
| func panicoverflow() { |
| panicCheckMalloc(overflowError) |
| panic(overflowError) |
| } |
| |
| var floatError = error(errorString("floating point error")) |
| |
| func panicfloat() { |
| panicCheckMalloc(floatError) |
| panic(floatError) |
| } |
| |
| var memoryError = error(errorString("invalid memory address or nil pointer dereference")) |
| |
| func panicmem() { |
| panicCheckMalloc(memoryError) |
| panic(memoryError) |
| } |
| |
| func throwinit() { |
| throw("recursive call during initialization - linker skew") |
| } |
| |
| // deferproc creates a new deferred function. |
| // The compiler turns a defer statement into a call to this. |
| // frame points into the stack frame; it is used to determine which |
| // deferred functions are for the current stack frame, and whether we |
| // have already deferred functions for this frame. |
| // pfn is a C function pointer. |
| // arg is a value to pass to pfn. |
| func deferproc(frame *bool, pfn uintptr, arg unsafe.Pointer) { |
| d := newdefer() |
| if d._panic != nil { |
| throw("deferproc: d.panic != nil after newdefer") |
| } |
| d.frame = frame |
| d.panicStack = getg()._panic |
| d.pfn = pfn |
| d.arg = arg |
| d.retaddr = 0 |
| d.makefunccanrecover = false |
| } |
| |
| // Allocate a Defer, usually using per-P pool. |
| // Each defer must be released with freedefer. |
| func newdefer() *_defer { |
| var d *_defer |
| gp := getg() |
| pp := gp.m.p.ptr() |
| if len(pp.deferpool) == 0 && sched.deferpool != nil { |
| systemstack(func() { |
| lock(&sched.deferlock) |
| for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil { |
| d := sched.deferpool |
| sched.deferpool = d.link |
| d.link = nil |
| pp.deferpool = append(pp.deferpool, d) |
| } |
| unlock(&sched.deferlock) |
| }) |
| } |
| if n := len(pp.deferpool); n > 0 { |
| d = pp.deferpool[n-1] |
| pp.deferpool[n-1] = nil |
| pp.deferpool = pp.deferpool[:n-1] |
| } |
| if d == nil { |
| systemstack(func() { |
| d = new(_defer) |
| }) |
| } |
| d.link = gp._defer |
| gp._defer = d |
| return d |
| } |
| |
| // Free the given defer. |
| // The defer cannot be used after this call. |
| // |
| // This must not grow the stack because there may be a frame without a |
| // stack map when this is called. |
| // |
| //go:nosplit |
| func freedefer(d *_defer) { |
| if d._panic != nil { |
| freedeferpanic() |
| } |
| if d.pfn != 0 { |
| freedeferfn() |
| } |
| pp := getg().m.p.ptr() |
| if len(pp.deferpool) == cap(pp.deferpool) { |
| // Transfer half of local cache to the central cache. |
| // |
| // Take this slow path on the system stack so |
| // we don't grow freedefer's stack. |
| systemstack(func() { |
| var first, last *_defer |
| for len(pp.deferpool) > cap(pp.deferpool)/2 { |
| n := len(pp.deferpool) |
| d := pp.deferpool[n-1] |
| pp.deferpool[n-1] = nil |
| pp.deferpool = pp.deferpool[:n-1] |
| if first == nil { |
| first = d |
| } else { |
| last.link = d |
| } |
| last = d |
| } |
| lock(&sched.deferlock) |
| last.link = sched.deferpool |
| sched.deferpool = first |
| unlock(&sched.deferlock) |
| }) |
| } |
| |
| // These lines used to be simply `*d = _defer{}` but that |
| // started causing a nosplit stack overflow via typedmemmove. |
| d.link = nil |
| d.frame = nil |
| d.panicStack = nil |
| d.arg = nil |
| d.retaddr = 0 |
| d.makefunccanrecover = false |
| // d._panic and d.pfn must be nil already. |
| // If not, we would have called freedeferpanic or freedeferfn above, |
| // both of which throw. |
| |
| pp.deferpool = append(pp.deferpool, d) |
| } |
| |
| // Separate function so that it can split stack. |
| // Windows otherwise runs out of stack space. |
| func freedeferpanic() { |
| // _panic must be cleared before d is unlinked from gp. |
| throw("freedefer with d._panic != nil") |
| } |
| |
| func freedeferfn() { |
| // fn must be cleared before d is unlinked from gp. |
| throw("freedefer with d.fn != nil") |
| } |
| |
| // deferreturn is called to undefer the stack. |
| // The compiler inserts a call to this function as a finally clause |
| // wrapped around the body of any function that calls defer. |
| // The frame argument points to the stack frame of the function. |
| func deferreturn(frame *bool) { |
| gp := getg() |
| for gp._defer != nil && gp._defer.frame == frame { |
| d := gp._defer |
| pfn := d.pfn |
| d.pfn = 0 |
| |
| if pfn != 0 { |
| // This is rather awkward. |
| // The gc compiler does this using assembler |
| // code in jmpdefer. |
| var fn func(unsafe.Pointer) |
| *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(noescape(unsafe.Pointer(&pfn))) |
| fn(d.arg) |
| } |
| |
| // If we are returning from a Go function called by a |
| // C function running in a C thread, g may now be nil, |
| // in which case CgocallBackDone will have cleared _defer. |
| // In that case some other goroutine may already be using gp. |
| if getg() == nil { |
| *frame = true |
| return |
| } |
| |
| gp._defer = d.link |
| |
| freedefer(d) |
| |
| // Since we are executing a defer function now, we |
| // know that we are returning from the calling |
| // function. If the calling function, or one of its |
| // callees, panicked, then the defer functions would |
| // be executed by panic. |
| *frame = true |
| } |
| } |
| |
| // __builtin_extract_return_addr is a GCC intrinsic that converts an |
| // address returned by __builtin_return_address(0) to a real address. |
| // On most architectures this is a nop. |
| //extern __builtin_extract_return_addr |
| func __builtin_extract_return_addr(uintptr) uintptr |
| |
| // setdeferretaddr records the address to which the deferred function |
| // returns. This is check by canrecover. The frontend relies on this |
| // function returning false. |
| func setdeferretaddr(retaddr uintptr) bool { |
| gp := getg() |
| if gp._defer != nil { |
| gp._defer.retaddr = __builtin_extract_return_addr(retaddr) |
| } |
| return false |
| } |
| |
| // checkdefer is called by exception handlers used when unwinding the |
| // stack after a recovered panic. The exception handler is simply |
| // checkdefer(frame) |
| // return; |
| // If we have not yet reached the frame we are looking for, we |
| // continue unwinding. |
| func checkdefer(frame *bool) { |
| gp := getg() |
| if gp == nil { |
| // We should never wind up here. Even if some other |
| // language throws an exception, the cgo code |
| // should ensure that g is set. |
| throw("no g in checkdefer") |
| } else if gp.isforeign { |
| // Some other language has thrown an exception. |
| // We need to run the local defer handlers. |
| // If they call recover, we stop unwinding here. |
| var p _panic |
| p.isforeign = true |
| p.link = gp._panic |
| gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) |
| for { |
| d := gp._defer |
| if d == nil || d.frame != frame || d.pfn == 0 { |
| break |
| } |
| |
| pfn := d.pfn |
| gp._defer = d.link |
| |
| var fn func(unsafe.Pointer) |
| *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(noescape(unsafe.Pointer(&pfn))) |
| fn(d.arg) |
| |
| freedefer(d) |
| |
| if p.recovered { |
| // The recover function caught the panic |
| // thrown by some other language. |
| break |
| } |
| } |
| |
| recovered := p.recovered |
| gp._panic = p.link |
| |
| if recovered { |
| // Just return and continue executing Go code. |
| *frame = true |
| return |
| } |
| |
| // We are panicking through this function. |
| *frame = false |
| } else if gp._defer != nil && gp._defer.pfn == 0 && gp._defer.frame == frame { |
| // This is the defer function that called recover. |
| // Simply return to stop the stack unwind, and let the |
| // Go code continue to execute. |
| d := gp._defer |
| gp._defer = d.link |
| freedefer(d) |
| |
| // We are returning from this function. |
| *frame = true |
| |
| return |
| } |
| |
| // This is some other defer function. It was already run by |
| // the call to panic, or just above. Rethrow the exception. |
| rethrowException() |
| throw("rethrowException returned") |
| } |
| |
| // unwindStack starts unwinding the stack for a panic. We unwind |
| // function calls until we reach the one which used a defer function |
| // which called recover. Each function which uses a defer statement |
| // will have an exception handler, as shown above for checkdefer. |
| func unwindStack() { |
| // Allocate the exception type used by the unwind ABI. |
| // It would be nice to define it in runtime_sysinfo.go, |
| // but current definitions don't work because the required |
| // alignment is larger than can be represented in Go. |
| // The type never contains any Go pointers. |
| size := unwindExceptionSize() |
| usize := uintptr(unsafe.Sizeof(uintptr(0))) |
| c := (size + usize - 1) / usize |
| s := make([]uintptr, c) |
| getg().exception = unsafe.Pointer(&s[0]) |
| throwException() |
| } |
| |
| // Goexit terminates the goroutine that calls it. No other goroutine is affected. |
| // Goexit runs all deferred calls before terminating the goroutine. Because Goexit |
| // is not a panic, any recover calls in those deferred functions will return nil. |
| // |
| // Calling Goexit from the main goroutine terminates that goroutine |
| // without func main returning. Since func main has not returned, |
| // the program continues execution of other goroutines. |
| // If all other goroutines exit, the program crashes. |
| func Goexit() { |
| // Run all deferred functions for the current goroutine. |
| // This code is similar to gopanic, see that implementation |
| // for detailed comments. |
| gp := getg() |
| for { |
| d := gp._defer |
| if d == nil { |
| break |
| } |
| |
| pfn := d.pfn |
| if pfn == 0 { |
| if d._panic != nil { |
| d._panic.aborted = true |
| d._panic = nil |
| } |
| gp._defer = d.link |
| freedefer(d) |
| continue |
| } |
| d.pfn = 0 |
| |
| var fn func(unsafe.Pointer) |
| *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(noescape(unsafe.Pointer(&pfn))) |
| fn(d.arg) |
| |
| if gp._defer != d { |
| throw("bad defer entry in Goexit") |
| } |
| d._panic = nil |
| gp._defer = d.link |
| freedefer(d) |
| // Note: we ignore recovers here because Goexit isn't a panic |
| } |
| goexit1() |
| } |
| |
| // Call all Error and String methods before freezing the world. |
| // Used when crashing with panicking. |
| func preprintpanics(p *_panic) { |
| defer func() { |
| if recover() != nil { |
| throw("panic while printing panic value") |
| } |
| }() |
| for p != nil { |
| switch v := p.arg.(type) { |
| case error: |
| p.arg = v.Error() |
| case stringer: |
| p.arg = v.String() |
| } |
| p = p.link |
| } |
| } |
| |
| // Print all currently active panics. Used when crashing. |
| // Should only be called after preprintpanics. |
| func printpanics(p *_panic) { |
| if p.link != nil { |
| printpanics(p.link) |
| print("\t") |
| } |
| print("panic: ") |
| printany(p.arg) |
| if p.recovered { |
| print(" [recovered]") |
| } |
| print("\n") |
| } |
| |
| // The implementation of the predeclared function panic. |
| func gopanic(e interface{}) { |
| gp := getg() |
| if gp.m.curg != gp { |
| print("panic: ") |
| printany(e) |
| print("\n") |
| throw("panic on system stack") |
| } |
| |
| if gp.m.mallocing != 0 { |
| print("panic: ") |
| printany(e) |
| print("\n") |
| throw("panic during malloc") |
| } |
| if gp.m.preemptoff != "" { |
| print("panic: ") |
| printany(e) |
| print("\n") |
| print("preempt off reason: ") |
| print(gp.m.preemptoff) |
| print("\n") |
| throw("panic during preemptoff") |
| } |
| if gp.m.locks != 0 { |
| print("panic: ") |
| printany(e) |
| print("\n") |
| throw("panic holding locks") |
| } |
| |
| // The gc compiler allocates this new _panic struct on the |
| // stack. We can't do that, because when a deferred function |
| // recovers the panic we unwind the stack. We unlink this |
| // entry before unwinding the stack, but that doesn't help in |
| // the case where we panic, a deferred function recovers and |
| // then panics itself, that panic is in turn recovered, and |
| // unwinds the stack past this stack frame. |
| |
| p := &_panic{ |
| arg: e, |
| link: gp._panic, |
| } |
| gp._panic = p |
| |
| atomic.Xadd(&runningPanicDefers, 1) |
| |
| for { |
| d := gp._defer |
| if d == nil { |
| break |
| } |
| |
| pfn := d.pfn |
| |
| // If defer was started by earlier panic or Goexit (and, since we're back here, that triggered a new panic), |
| // take defer off list. The earlier panic or Goexit will not continue running. |
| if pfn == 0 { |
| if d._panic != nil { |
| d._panic.aborted = true |
| } |
| d._panic = nil |
| gp._defer = d.link |
| freedefer(d) |
| continue |
| } |
| d.pfn = 0 |
| |
| // Record the panic that is running the defer. |
| // If there is a new panic during the deferred call, that panic |
| // will find d in the list and will mark d._panic (this panic) aborted. |
| d._panic = p |
| |
| var fn func(unsafe.Pointer) |
| *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(noescape(unsafe.Pointer(&pfn))) |
| fn(d.arg) |
| |
| if gp._defer != d { |
| throw("bad defer entry in panic") |
| } |
| d._panic = nil |
| |
| if p.recovered { |
| atomic.Xadd(&runningPanicDefers, -1) |
| |
| gp._panic = p.link |
| |
| // Aborted panics are marked but remain on the g.panic list. |
| // Remove them from the list. |
| for gp._panic != nil && gp._panic.aborted { |
| gp._panic = gp._panic.link |
| } |
| if gp._panic == nil { // must be done with signal |
| gp.sig = 0 |
| } |
| |
| // Unwind the stack by throwing an exception. |
| // The compiler has arranged to create |
| // exception handlers in each function |
| // that uses a defer statement. These |
| // exception handlers will check whether |
| // the entry on the top of the defer stack |
| // is from the current function. If it is, |
| // we have unwound the stack far enough. |
| unwindStack() |
| |
| throw("unwindStack returned") |
| } |
| |
| // Because we executed that defer function by a panic, |
| // and it did not call recover, we know that we are |
| // not returning from the calling function--we are |
| // panicking through it. |
| *d.frame = false |
| |
| // Deferred function did not panic. Remove d. |
| // In the p.recovered case, d will be removed by checkdefer. |
| gp._defer = d.link |
| |
| freedefer(d) |
| } |
| |
| // ran out of deferred calls - old-school panic now |
| // Because it is unsafe to call arbitrary user code after freezing |
| // the world, we call preprintpanics to invoke all necessary Error |
| // and String methods to prepare the panic strings before startpanic. |
| preprintpanics(gp._panic) |
| |
| fatalpanic(gp._panic) // should not return |
| *(*int)(nil) = 0 // not reached |
| } |
| |
| // currentDefer returns the top of the defer stack if it can be recovered. |
| // Otherwise it returns nil. |
| func currentDefer() *_defer { |
| gp := getg() |
| d := gp._defer |
| if d == nil { |
| return nil |
| } |
| |
| // The panic that would be recovered is the one on the top of |
| // the panic stack. We do not want to recover it if that panic |
| // was on the top of the panic stack when this function was |
| // deferred. |
| if d.panicStack == gp._panic { |
| return nil |
| } |
| |
| // The deferred thunk will call setdeferretaddr. If this has |
| // not happened, then we have not been called via defer, and |
| // we can not recover. |
| if d.retaddr == 0 { |
| return nil |
| } |
| |
| return d |
| } |
| |
| // canrecover is called by a thunk to see if the real function would |
| // be permitted to recover a panic value. Recovering a value is |
| // permitted if the thunk was called directly by defer. retaddr is the |
| // return address of the function that is calling canrecover--that is, |
| // the thunk. |
| func canrecover(retaddr uintptr) bool { |
| d := currentDefer() |
| if d == nil { |
| return false |
| } |
| |
| ret := __builtin_extract_return_addr(retaddr) |
| dret := d.retaddr |
| if ret <= dret && ret+16 >= dret { |
| return true |
| } |
| |
| // On some systems, in some cases, the return address does not |
| // work reliably. See http://gcc.gnu.org/PR60406. If we are |
| // permitted to call recover, the call stack will look like this: |
| // runtime.gopanic, runtime.deferreturn, etc. |
| // thunk to call deferred function (calls __go_set_defer_retaddr) |
| // function that calls __go_can_recover (passing return address) |
| // runtime.canrecover |
| // Calling callers will skip the thunks. So if our caller's |
| // caller starts with "runtime.", then we are permitted to |
| // call recover. |
| var locs [16]location |
| if callers(1, locs[:2]) < 2 { |
| return false |
| } |
| |
| name := locs[1].function |
| if hasprefix(name, "runtime.") { |
| return true |
| } |
| |
| // If the function calling recover was created by reflect.MakeFunc, |
| // then makefuncfficanrecover will have set makefunccanrecover. |
| if !d.makefunccanrecover { |
| return false |
| } |
| |
| // We look up the stack, ignoring libffi functions and |
| // functions in the reflect package, until we find |
| // reflect.makeFuncStub or reflect.ffi_callback called by FFI |
| // functions. Then we check the caller of that function. |
| |
| n := callers(2, locs[:]) |
| foundFFICallback := false |
| i := 0 |
| for ; i < n; i++ { |
| name = locs[i].function |
| if name == "" { |
| // No function name means this caller isn't Go code. |
| // Assume that this is libffi. |
| continue |
| } |
| |
| // Ignore function in libffi. |
| if hasprefix(name, "ffi_") { |
| continue |
| } |
| |
| if foundFFICallback { |
| break |
| } |
| |
| if name == "reflect.ffi_callback" { |
| foundFFICallback = true |
| continue |
| } |
| |
| // Ignore other functions in the reflect package. |
| if hasprefix(name, "reflect.") || hasprefix(name, ".1reflect.") { |
| continue |
| } |
| |
| // We should now be looking at the real caller. |
| break |
| } |
| |
| if i < n { |
| name = locs[i].function |
| if hasprefix(name, "runtime.") { |
| return true |
| } |
| } |
| |
| return false |
| } |
| |
| // This function is called when code is about to enter a function |
| // created by the libffi version of reflect.MakeFunc. This function is |
| // passed the names of the callers of the libffi code that called the |
| // stub. It uses them to decide whether it is permitted to call |
| // recover, and sets d.makefunccanrecover so that gorecover can make |
| // the same decision. |
| func makefuncfficanrecover(loc []location) { |
| d := currentDefer() |
| if d == nil { |
| return |
| } |
| |
| // If we are already in a call stack of MakeFunc functions, |
| // there is nothing we can usefully check here. |
| if d.makefunccanrecover { |
| return |
| } |
| |
| // loc starts with the caller of our caller. That will be a thunk. |
| // If its caller was a function function, then it was called |
| // directly by defer. |
| if len(loc) < 2 { |
| return |
| } |
| |
| name := loc[1].function |
| if hasprefix(name, "runtime.") { |
| d.makefunccanrecover = true |
| } |
| } |
| |
| // makefuncreturning is called when code is about to exit a function |
| // created by reflect.MakeFunc. It is called by the function stub used |
| // by reflect.MakeFunc. It clears the makefunccanrecover field. It's |
| // OK to always clear this field, because canrecover will only be |
| // called by a stub created for a function that calls recover. That |
| // stub will not call a function created by reflect.MakeFunc, so by |
| // the time we get here any caller higher up on the call stack no |
| // longer needs the information. |
| func makefuncreturning() { |
| d := getg()._defer |
| if d != nil { |
| d.makefunccanrecover = false |
| } |
| } |
| |
| // The implementation of the predeclared function recover. |
| func gorecover() interface{} { |
| gp := getg() |
| p := gp._panic |
| if p != nil && !p.recovered { |
| p.recovered = true |
| return p.arg |
| } |
| return nil |
| } |
| |
| // deferredrecover is called when a call to recover is deferred. That |
| // is, something like |
| // defer recover() |
| // |
| // We need to handle this specially. In gc, the recover function |
| // looks up the stack frame. In particular, that means that a deferred |
| // recover will not recover a panic thrown in the same function that |
| // defers the recover. It will only recover a panic thrown in a |
| // function that defers the deferred call to recover. |
| // |
| // In other words: |
| // |
| // func f1() { |
| // defer recover() // does not stop panic |
| // panic(0) |
| // } |
| // |
| // func f2() { |
| // defer func() { |
| // defer recover() // stops panic(0) |
| // }() |
| // panic(0) |
| // } |
| // |
| // func f3() { |
| // defer func() { |
| // defer recover() // does not stop panic |
| // panic(0) |
| // }() |
| // panic(1) |
| // } |
| // |
| // func f4() { |
| // defer func() { |
| // defer func() { |
| // defer recover() // stops panic(0) |
| // }() |
| // panic(0) |
| // }() |
| // panic(1) |
| // } |
| // |
| // The interesting case here is f3. As can be seen from f2, the |
| // deferred recover could pick up panic(1). However, this does not |
| // happen because it is blocked by the panic(0). |
| // |
| // When a function calls recover, then when we invoke it we pass a |
| // hidden parameter indicating whether it should recover something. |
| // This parameter is set based on whether the function is being |
| // invoked directly from defer. The parameter winds up determining |
| // whether __go_recover or __go_deferred_recover is called at all. |
| // |
| // In the case of a deferred recover, the hidden parameter that |
| // controls the call is actually the one set up for the function that |
| // runs the defer recover() statement. That is the right thing in all |
| // the cases above except for f3. In f3 the function is permitted to |
| // call recover, but the deferred recover call is not. We address that |
| // here by checking for that specific case before calling recover. If |
| // this function was deferred when there is already a panic on the |
| // panic stack, then we can only recover that panic, not any other. |
| |
| // Note that we can get away with using a special function here |
| // because you are not permitted to take the address of a predeclared |
| // function like recover. |
| func deferredrecover() interface{} { |
| gp := getg() |
| if gp._defer == nil || gp._defer.panicStack != gp._panic { |
| return nil |
| } |
| return gorecover() |
| } |
| |
| //go:linkname sync_throw sync.throw |
| func sync_throw(s string) { |
| throw(s) |
| } |
| |
| //go:nosplit |
| func throw(s string) { |
| // Everything throw does should be recursively nosplit so it |
| // can be called even when it's unsafe to grow the stack. |
| systemstack(func() { |
| print("fatal error: ", s, "\n") |
| }) |
| gp := getg() |
| if gp.m.throwing == 0 { |
| gp.m.throwing = 1 |
| } |
| fatalthrow() |
| *(*int)(nil) = 0 // not reached |
| } |
| |
| // runningPanicDefers is non-zero while running deferred functions for panic. |
| // runningPanicDefers is incremented and decremented atomically. |
| // This is used to try hard to get a panic stack trace out when exiting. |
| var runningPanicDefers uint32 |
| |
| // panicking is non-zero when crashing the program for an unrecovered panic. |
| // panicking is incremented and decremented atomically. |
| var panicking uint32 |
| |
| // paniclk is held while printing the panic information and stack trace, |
| // so that two concurrent panics don't overlap their output. |
| var paniclk mutex |
| |
| // fatalthrow implements an unrecoverable runtime throw. It freezes the |
| // system, prints stack traces starting from its caller, and terminates the |
| // process. |
| // |
| //go:nosplit |
| func fatalthrow() { |
| pc := getcallerpc() |
| sp := getcallersp() |
| gp := getg() |
| |
| startpanic_m() |
| |
| if dopanic_m(gp, pc, sp) { |
| crash() |
| } |
| |
| exit(2) |
| |
| *(*int)(nil) = 0 // not reached |
| } |
| |
| // fatalpanic implements an unrecoverable panic. It is like fatalthrow, except |
| // that if msgs != nil, fatalpanic also prints panic messages and decrements |
| // runningPanicDefers once main is blocked from exiting. |
| // |
| //go:nosplit |
| func fatalpanic(msgs *_panic) { |
| pc := getcallerpc() |
| sp := getcallersp() |
| gp := getg() |
| var docrash bool |
| |
| if startpanic_m() && msgs != nil { |
| // There were panic messages and startpanic_m |
| // says it's okay to try to print them. |
| |
| // startpanic_m set panicking, which will |
| // block main from exiting, so now OK to |
| // decrement runningPanicDefers. |
| atomic.Xadd(&runningPanicDefers, -1) |
| |
| printpanics(msgs) |
| } |
| |
| docrash = dopanic_m(gp, pc, sp) |
| |
| if docrash { |
| // By crashing outside the above systemstack call, debuggers |
| // will not be confused when generating a backtrace. |
| // Function crash is marked nosplit to avoid stack growth. |
| crash() |
| } |
| |
| systemstack(func() { |
| exit(2) |
| }) |
| |
| *(*int)(nil) = 0 // not reached |
| } |
| |
| // startpanic_m prepares for an unrecoverable panic. |
| // |
| // It returns true if panic messages should be printed, or false if |
| // the runtime is in bad shape and should just print stacks. |
| // |
| // It can have write barriers because the write barrier explicitly |
| // ignores writes once dying > 0. |
| // |
| //go:yeswritebarrierrec |
| func startpanic_m() bool { |
| _g_ := getg() |
| if mheap_.cachealloc.size == 0 { // very early |
| print("runtime: panic before malloc heap initialized\n") |
| } |
| // Disallow malloc during an unrecoverable panic. A panic |
| // could happen in a signal handler, or in a throw, or inside |
| // malloc itself. We want to catch if an allocation ever does |
| // happen (even if we're not in one of these situations). |
| _g_.m.mallocing++ |
| |
| // If we're dying because of a bad lock count, set it to a |
| // good lock count so we don't recursively panic below. |
| if _g_.m.locks < 0 { |
| _g_.m.locks = 1 |
| } |
| |
| switch _g_.m.dying { |
| case 0: |
| _g_.m.dying = 1 |
| _g_.writebuf = nil |
| atomic.Xadd(&panicking, 1) |
| lock(&paniclk) |
| if debug.schedtrace > 0 || debug.scheddetail > 0 { |
| schedtrace(true) |
| } |
| freezetheworld() |
| return true |
| case 1: |
| // Something failed while panicking. |
| // Just print a stack trace and exit. |
| _g_.m.dying = 2 |
| print("panic during panic\n") |
| return false |
| case 2: |
| // This is a genuine bug in the runtime, we couldn't even |
| // print the stack trace successfully. |
| _g_.m.dying = 3 |
| print("stack trace unavailable\n") |
| exit(4) |
| fallthrough |
| default: |
| // Can't even print! Just exit. |
| exit(5) |
| return false // Need to return something. |
| } |
| } |
| |
| var didothers bool |
| var deadlock mutex |
| |
| func dopanic_m(gp *g, pc, sp uintptr) bool { |
| if gp.sig != 0 { |
| signame := signame(gp.sig) |
| if signame != "" { |
| print("[signal ", signame) |
| } else { |
| print("[signal ", hex(gp.sig)) |
| } |
| print(" code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n") |
| } |
| |
| level, all, docrash := gotraceback() |
| _g_ := getg() |
| if level > 0 { |
| if gp != gp.m.curg { |
| all = true |
| } |
| if gp != gp.m.g0 { |
| print("\n") |
| goroutineheader(gp) |
| traceback(0) |
| } else if level >= 2 || _g_.m.throwing > 0 { |
| print("\nruntime stack:\n") |
| traceback(0) |
| } |
| if !didothers && all { |
| didothers = true |
| tracebackothers(gp) |
| } |
| } |
| unlock(&paniclk) |
| |
| if atomic.Xadd(&panicking, -1) != 0 { |
| // Some other m is panicking too. |
| // Let it print what it needs to print. |
| // Wait forever without chewing up cpu. |
| // It will exit when it's done. |
| lock(&deadlock) |
| lock(&deadlock) |
| } |
| |
| return docrash |
| } |
| |
| // canpanic returns false if a signal should throw instead of |
| // panicking. |
| // |
| //go:nosplit |
| func canpanic(gp *g) bool { |
| // Note that g is m->gsignal, different from gp. |
| // Note also that g->m can change at preemption, so m can go stale |
| // if this function ever makes a function call. |
| _g_ := getg() |
| _m_ := _g_.m |
| |
| // Is it okay for gp to panic instead of crashing the program? |
| // Yes, as long as it is running Go code, not runtime code, |
| // and not stuck in a system call. |
| if gp == nil || gp != _m_.curg { |
| return false |
| } |
| if _m_.locks != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 { |
| return false |
| } |
| status := readgstatus(gp) |
| if status&^_Gscan != _Grunning || gp.syscallsp != 0 { |
| return false |
| } |
| return true |
| } |
| |
| // isAbortPC returns true if pc is the program counter at which |
| // runtime.abort raises a signal. |
| // |
| // It is nosplit because it's part of the isgoexception |
| // implementation. |
| // |
| //go:nosplit |
| func isAbortPC(pc uintptr) bool { |
| return false |
| } |