| // 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 export compiler-called functions. | |
| // | |
| //go:linkname deferproc | |
| //go:linkname deferprocStack | |
| //go:linkname deferreturn | |
| //go:linkname setdeferretaddr | |
| //go:linkname checkdefer | |
| //go:linkname gopanic | |
| //go:linkname canrecover | |
| //go:linkname makefuncfficanrecover | |
| //go:linkname makefuncreturning | |
| //go:linkname gorecover | |
| //go:linkname deferredrecover | |
| //go:linkname goPanicIndex | |
| //go:linkname goPanicIndexU | |
| //go:linkname goPanicSliceAlen | |
| //go:linkname goPanicSliceAlenU | |
| //go:linkname goPanicSliceAcap | |
| //go:linkname goPanicSliceAcapU | |
| //go:linkname goPanicSliceB | |
| //go:linkname goPanicSliceBU | |
| //go:linkname goPanicSlice3Alen | |
| //go:linkname goPanicSlice3AlenU | |
| //go:linkname goPanicSlice3Acap | |
| //go:linkname goPanicSlice3AcapU | |
| //go:linkname goPanicSlice3B | |
| //go:linkname goPanicSlice3BU | |
| //go:linkname goPanicSlice3C | |
| //go:linkname goPanicSlice3CU | |
| //go:linkname goPanicSliceConvert | |
| //go:linkname panicshift | |
| //go:linkname panicdivide | |
| //go:linkname panicmem | |
| // Temporary for C code to call: | |
| //go:linkname throw | |
| // Check to make sure we can really generate a panic. If the panic | |
| // was generated from the runtime, or from inside malloc, then convert | |
| // to a throw of msg. | |
| // pc should be the program counter of the compiler-generated code that | |
| // triggered this panic. | |
| func panicCheck1(pc uintptr, msg string) { | |
| name, _, _, _ := funcfileline(pc-1, -1, false) | |
| if hasPrefix(name, "runtime.") { | |
| throw(msg) | |
| } | |
| // TODO: is this redundant? How could we be in malloc | |
| // but not in the runtime? runtime/internal/*, maybe? | |
| gp := getg() | |
| if gp != nil && gp.m != nil && gp.m.mallocing != 0 { | |
| throw(msg) | |
| } | |
| } | |
| // Same as above, but calling from the runtime is allowed. | |
| // | |
| // Using this function is necessary for any panic that may be | |
| // generated by runtime.sigpanic, since those are always called by the | |
| // runtime. | |
| func panicCheck2(err string) { | |
| // panic allocates, so to avoid recursive malloc, turn panics | |
| // during malloc into throws. | |
| gp := getg() | |
| if gp != nil && gp.m != nil && gp.m.mallocing != 0 { | |
| throw(err) | |
| } | |
| } | |
| // Many of the following panic entry-points turn into throws when they | |
| // happen in various runtime contexts. These should never happen in | |
| // the runtime, and if they do, they indicate a serious issue and | |
| // should not be caught by user code. | |
| // | |
| // The panic{Index,Slice,divide,shift} functions are called by | |
| // code generated by the compiler for out of bounds index expressions, | |
| // out of bounds slice expressions, division by zero, and shift by negative. | |
| // The panicdivide (again), panicoverflow, panicfloat, and panicmem | |
| // functions are called by the signal handler when a signal occurs | |
| // indicating the respective problem. | |
| // | |
| // Since panic{Index,Slice,shift} are never called directly, and | |
| // since the runtime package should never have an out of bounds slice | |
| // or array reference or negative shift, 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. | |
| // | |
| // The entry points called by the signal handler will be called from | |
| // runtime.sigpanic, so we can't disallow calls from the runtime to | |
| // these (they always look like they're called from the runtime). | |
| // Hence, for these, we just check for clearly bad runtime conditions. | |
| // failures in the comparisons for s[x], 0 <= x < y (y == len(s)) | |
| func goPanicIndex(x int, y int) { | |
| panicCheck1(getcallerpc(), "index out of range") | |
| panic(boundsError{x: int64(x), signed: true, y: y, code: boundsIndex}) | |
| } | |
| func goPanicIndexU(x uint, y int) { | |
| panicCheck1(getcallerpc(), "index out of range") | |
| panic(boundsError{x: int64(x), signed: false, y: y, code: boundsIndex}) | |
| } | |
| // failures in the comparisons for s[:x], 0 <= x <= y (y == len(s) or cap(s)) | |
| func goPanicSliceAlen(x int, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAlen}) | |
| } | |
| func goPanicSliceAlenU(x uint, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAlen}) | |
| } | |
| func goPanicSliceAcap(x int, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAcap}) | |
| } | |
| func goPanicSliceAcapU(x uint, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAcap}) | |
| } | |
| // failures in the comparisons for s[x:y], 0 <= x <= y | |
| func goPanicSliceB(x int, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceB}) | |
| } | |
| func goPanicSliceBU(x uint, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceB}) | |
| } | |
| // failures in the comparisons for s[::x], 0 <= x <= y (y == len(s) or cap(s)) | |
| func goPanicSlice3Alen(x int, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Alen}) | |
| } | |
| func goPanicSlice3AlenU(x uint, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Alen}) | |
| } | |
| func goPanicSlice3Acap(x int, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Acap}) | |
| } | |
| func goPanicSlice3AcapU(x uint, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Acap}) | |
| } | |
| // failures in the comparisons for s[:x:y], 0 <= x <= y | |
| func goPanicSlice3B(x int, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3B}) | |
| } | |
| func goPanicSlice3BU(x uint, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3B}) | |
| } | |
| // failures in the comparisons for s[x:y:], 0 <= x <= y | |
| func goPanicSlice3C(x int, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3C}) | |
| } | |
| func goPanicSlice3CU(x uint, y int) { | |
| panicCheck1(getcallerpc(), "slice bounds out of range") | |
| panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3C}) | |
| } | |
| // failures in the conversion (*[x]T)s, 0 <= x <= y, x == cap(s) | |
| func goPanicSliceConvert(x int, y int) { | |
| panicCheck1(getcallerpc(), "slice length too short to convert to pointer to array") | |
| panic(boundsError{x: int64(x), signed: true, y: y, code: boundsConvert}) | |
| } | |
| var shiftError = error(errorString("negative shift amount")) | |
| func panicshift() { | |
| panicCheck1(getcallerpc(), "negative shift amount") | |
| panic(shiftError) | |
| } | |
| var divideError = error(errorString("integer divide by zero")) | |
| func panicdivide() { | |
| panicCheck2("integer divide by zero") | |
| panic(divideError) | |
| } | |
| var overflowError = error(errorString("integer overflow")) | |
| func panicoverflow() { | |
| panicCheck2("integer overflow") | |
| panic(overflowError) | |
| } | |
| var floatError = error(errorString("floating point error")) | |
| func panicfloat() { | |
| panicCheck2("floating point error") | |
| panic(floatError) | |
| } | |
| var memoryError = error(errorString("invalid memory address or nil pointer dereference")) | |
| func panicmem() { | |
| panicCheck2("invalid memory address or nil pointer dereference") | |
| panic(memoryError) | |
| } | |
| func panicmemAddr(addr uintptr) { | |
| panicCheck2("invalid memory address or nil pointer dereference") | |
| panic(errorAddressString{msg: "invalid memory address or nil pointer dereference", addr: addr}) | |
| } | |
| // 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) { | |
| gp := getg() | |
| d := newdefer() | |
| if d._panic != nil { | |
| throw("deferproc: d.panic != nil after newdefer") | |
| } | |
| d.link = gp._defer | |
| gp._defer = d | |
| d.frame = frame | |
| d.panicStack = getg()._panic | |
| d.pfn = pfn | |
| d.arg = arg | |
| d.retaddr = 0 | |
| d.makefunccanrecover = false | |
| } | |
| // deferprocStack queues a new deferred function with a defer record on the stack. | |
| // The defer record, d, does not need to be initialized. | |
| // Other arguments are the same as in deferproc. | |
| //go:nosplit | |
| func deferprocStack(d *_defer, frame *bool, pfn uintptr, arg unsafe.Pointer) { | |
| gp := getg() | |
| if gp.m.curg != gp { | |
| // go code on the system stack can't defer | |
| throw("defer on system stack") | |
| } | |
| d.pfn = pfn | |
| d.retaddr = 0 | |
| d.makefunccanrecover = false | |
| d.heap = false | |
| // The lines below implement: | |
| // d.frame = frame | |
| // d.arg = arg | |
| // d._panic = nil | |
| // d.panicStack = gp._panic | |
| // d.link = gp._defer | |
| // But without write barriers. They are writes to the stack so they | |
| // don't need a write barrier, and furthermore are to uninitialized | |
| // memory, so they must not use a write barrier. | |
| *(*uintptr)(unsafe.Pointer(&d.frame)) = uintptr(unsafe.Pointer(frame)) | |
| *(*uintptr)(unsafe.Pointer(&d.arg)) = uintptr(unsafe.Pointer(arg)) | |
| *(*uintptr)(unsafe.Pointer(&d._panic)) = 0 | |
| *(*uintptr)(unsafe.Pointer(&d.panicStack)) = uintptr(unsafe.Pointer(gp._panic)) | |
| *(*uintptr)(unsafe.Pointer(&d.link)) = uintptr(unsafe.Pointer(gp._defer)) | |
| gp._defer = d | |
| } | |
| // Allocate a Defer, usually using per-P pool. | |
| // Each defer must be released with freedefer. | |
| func newdefer() *_defer { | |
| var d *_defer | |
| mp := acquirem() | |
| pp := mp.p.ptr() | |
| if len(pp.deferpool) == 0 && sched.deferpool != nil { | |
| 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] | |
| } | |
| releasem(mp) | |
| mp, pp = nil, nil | |
| if d == nil { | |
| // Allocate new defer. | |
| d = new(_defer) | |
| } | |
| d.heap = true | |
| return d | |
| } | |
| // Free the given defer. | |
| // The defer cannot be used after this call. | |
| // | |
| // This is nosplit because the incoming defer is in a perilous state. | |
| // It's not on any defer list, so stack copying won't adjust stack | |
| // pointers in it (namely, d.link). Hence, if we were to copy the | |
| // stack, d could then contain a stale pointer. | |
| // | |
| //go:nosplit | |
| func freedefer(d *_defer) { | |
| d.link = nil | |
| // After this point we can copy the stack. | |
| if d._panic != nil { | |
| freedeferpanic() | |
| } | |
| if d.pfn != 0 { | |
| freedeferfn() | |
| } | |
| if !d.heap { | |
| return | |
| } | |
| mp := acquirem() | |
| pp := mp.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) | |
| }) | |
| } | |
| *d = _defer{} | |
| pp.deferpool = append(pp.deferpool, d) | |
| releasem(mp) | |
| mp, pp = nil, nil | |
| } | |
| // 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))) | |
| gp.deferring = true | |
| fn(d.arg) | |
| gp.deferring = false | |
| } | |
| // If that was CgocallBackDone, it will have freed the | |
| // defer for us, since we are no longer running as Go code. | |
| if getg() == nil { | |
| *frame = true | |
| return | |
| } | |
| if gp.ranCgocallBackDone { | |
| gp.ranCgocallBackDone = false | |
| *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))) | |
| gp.deferring = true | |
| fn(d.arg) | |
| gp.deferring = false | |
| 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() | |
| gp.goexiting = true | |
| // Create a panic object for Goexit, so we can recognize when it might be | |
| // bypassed by a recover(). | |
| var p _panic | |
| p.goexit = true | |
| p.link = gp._panic | |
| gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) | |
| 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))) | |
| gp.deferring = true | |
| fn(d.arg) | |
| gp.deferring = false | |
| 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 | |
| } | |
| gp.goexiting = false | |
| 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) | |
| if !p.link.goexit { | |
| print("\t") | |
| } | |
| } | |
| if p.goexit { | |
| return | |
| } | |
| print("panic: ") | |
| printany(p.arg) | |
| if p.recovered { | |
| print(" [recovered]") | |
| } | |
| print("\n") | |
| } | |
| // The implementation of the predeclared function panic. | |
| func gopanic(e any) { | |
| 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))) | |
| gp.deferring = true | |
| fn(d.arg) | |
| gp.deferring = false | |
| if gp._defer != d { | |
| throw("bad defer entry in panic") | |
| } | |
| d._panic = nil | |
| if p.recovered { | |
| gp._panic = p.link | |
| if gp._panic != nil && gp._panic.goexit && gp._panic.aborted { | |
| Goexit() | |
| throw("Goexit returned") | |
| } | |
| atomic.Xadd(&runningPanicDefers, -1) | |
| // 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 | |
| } | |
| if gp._panic != nil && gp._panic.goexit { | |
| Goexit() | |
| throw("Goexit returned") | |
| } | |
| // 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.goexit && !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 must not have write barriers even though the write barrier | |
| // explicitly ignores writes once dying > 0. Write barriers still | |
| // assume that g.m.p != nil, and this function may not have P | |
| // in some contexts (e.g. a panic in a signal handler for a signal | |
| // sent to an M with no P). | |
| // | |
| //go:nowritebarrierrec | |
| 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: | |
| // Setting dying >0 has the side-effect of disabling this G's writebuf. | |
| _g_.m.dying = 1 | |
| 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) | |
| } | |
| printDebugLog() | |
| 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() | |
| mp := _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 != mp.curg { | |
| return false | |
| } | |
| if mp.locks != 0 || mp.mallocing != 0 || mp.throwing != 0 || mp.preemptoff != "" || mp.dying != 0 { | |
| return false | |
| } | |
| status := readgstatus(gp) | |
| if status&^_Gscan != _Grunning || gp.syscallsp != 0 { | |
| return false | |
| } | |
| return true | |
| } | |
| // isAbortPC reports whether 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 | |
| } |