diff options
Diffstat (limited to 'src/runtime/panic.go')
-rw-r--r-- | src/runtime/panic.go | 40 |
1 files changed, 22 insertions, 18 deletions
diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 121f2022a4..3783e3dede 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -1190,7 +1190,7 @@ func fatalpanic(msgs *_panic) { // //go:nowritebarrierrec func startpanic_m() bool { - _g_ := getg() + gp := getg() if mheap_.cachealloc.size == 0 { // very early print("runtime: panic before malloc heap initialized\n") } @@ -1198,18 +1198,18 @@ func startpanic_m() bool { // 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++ + gp.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 + if gp.m.locks < 0 { + gp.m.locks = 1 } - switch _g_.m.dying { + switch gp.m.dying { case 0: // Setting dying >0 has the side-effect of disabling this G's writebuf. - _g_.m.dying = 1 + gp.m.dying = 1 atomic.Xadd(&panicking, 1) lock(&paniclk) if debug.schedtrace > 0 || debug.scheddetail > 0 { @@ -1220,13 +1220,13 @@ func startpanic_m() bool { case 1: // Something failed while panicking. // Just print a stack trace and exit. - _g_.m.dying = 2 + gp.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 + gp.m.dying = 3 print("stack trace unavailable\n") exit(4) fallthrough @@ -1240,6 +1240,8 @@ func startpanic_m() bool { var didothers bool var deadlock mutex +// gp is the crashing g running on this M, but may be a user G, while getg() is +// always g0. func dopanic_m(gp *g, pc, sp uintptr) bool { if gp.sig != 0 { signame := signame(gp.sig) @@ -1252,7 +1254,6 @@ func dopanic_m(gp *g, pc, sp uintptr) bool { } level, all, docrash := gotraceback() - _g_ := getg() if level > 0 { if gp != gp.m.curg { all = true @@ -1261,7 +1262,7 @@ func dopanic_m(gp *g, pc, sp uintptr) bool { print("\n") goroutineheader(gp) traceback(pc, sp, 0, gp) - } else if level >= 2 || _g_.m.throwing >= throwTypeRuntime { + } else if level >= 2 || gp.m.throwing >= throwTypeRuntime { print("\nruntime stack:\n") traceback(pc, sp, 0, gp) } @@ -1290,29 +1291,32 @@ func dopanic_m(gp *g, pc, sp uintptr) bool { // 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 +func canpanic() bool { + gp := getg() + mp := acquirem() // 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 { + if gp != mp.curg { + releasem(mp) return false } - if mp.locks != 0 || mp.mallocing != 0 || mp.throwing != throwTypeNone || mp.preemptoff != "" || mp.dying != 0 { + // N.B. mp.locks != 1 instead of 0 to account for acquirem. + if mp.locks != 1 || mp.mallocing != 0 || mp.throwing != throwTypeNone || mp.preemptoff != "" || mp.dying != 0 { + releasem(mp) return false } status := readgstatus(gp) if status&^_Gscan != _Grunning || gp.syscallsp != 0 { + releasem(mp) return false } if GOOS == "windows" && mp.libcallsp != 0 { + releasem(mp) return false } + releasem(mp) return true } |