mirror of
https://github.com/golang/go
synced 2024-11-23 18:10:04 -07:00
cmd/link: fix nosplit stack overflow checks
The nosplit stack overflow checks were confused about morestack. The comment about not having correct SP information at the call to morestack was true, but that was a real bug, not something to work around. I fixed that problem in CL 12144. With that fixed, no need to special-case morestack in the way done here. This cleanup and simplification of the code was the first step to fixing a bug that happened when I started working on the arm64 frame size adjustments, but the cleanup was sufficient to make the bug go away. For #9880. Change-Id: I16b69a5c16b6b8cb4090295d3029c42d606e3b9b Reviewed-on: https://go-review.googlesource.com/12846 Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
parent
421220571d
commit
767e065809
@ -1465,10 +1465,7 @@ type Chain struct {
|
||||
limit int // limit on entry to sym
|
||||
}
|
||||
|
||||
var (
|
||||
morestack *LSym
|
||||
newstack *LSym
|
||||
)
|
||||
var morestack *LSym
|
||||
|
||||
// TODO: Record enough information in new object files to
|
||||
// allow stack checks here.
|
||||
@ -1488,7 +1485,6 @@ func dostkcheck() {
|
||||
var ch Chain
|
||||
|
||||
morestack = Linklookup(Ctxt, "runtime.morestack", 0)
|
||||
newstack = Linklookup(Ctxt, "runtime.newstack", 0)
|
||||
|
||||
// Every splitting function ensures that there are at least StackLimit
|
||||
// bytes available below SP when the splitting prologue finishes.
|
||||
@ -1533,7 +1529,8 @@ func stkcheck(up *Chain, depth int) int {
|
||||
|
||||
// Don't duplicate work: only need to consider each
|
||||
// function at top of safe zone once.
|
||||
if limit == obj.StackLimit-callsize() {
|
||||
top := limit == obj.StackLimit-callsize()
|
||||
if top {
|
||||
if s.Stkcheck != 0 {
|
||||
return 0
|
||||
}
|
||||
@ -1571,39 +1568,21 @@ func stkcheck(up *Chain, depth int) int {
|
||||
var ch Chain
|
||||
ch.up = up
|
||||
|
||||
// Check for a call to morestack anywhere and treat it
|
||||
// as occurring at function entry.
|
||||
// The decision about whether to call morestack occurs
|
||||
// in the prolog, but the call site is near the end
|
||||
// of the function on some architectures.
|
||||
// This is needed because the stack check is flow-insensitive,
|
||||
// so it incorrectly thinks the call to morestack happens wherever it shows up.
|
||||
// This check will be wrong if there are any hand-inserted calls to morestack.
|
||||
// There are not any now, nor should there ever be.
|
||||
for _, r := range s.R {
|
||||
if r.Sym == nil || !strings.HasPrefix(r.Sym.Name, "runtime.morestack") {
|
||||
continue
|
||||
}
|
||||
// Ignore non-calls to morestack, such as the jump to morestack
|
||||
// found in the implementation of morestack_noctxt.
|
||||
switch r.Type {
|
||||
default:
|
||||
continue
|
||||
case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER:
|
||||
}
|
||||
|
||||
if s.Nosplit == 0 {
|
||||
// Ensure we have enough stack to call morestack.
|
||||
ch.limit = limit - callsize()
|
||||
ch.sym = r.Sym
|
||||
ch.sym = morestack
|
||||
if stkcheck(&ch, depth+1) < 0 {
|
||||
return -1
|
||||
}
|
||||
// Bump up the limit.
|
||||
if !top {
|
||||
return 0
|
||||
}
|
||||
// Raise limit to allow frame.
|
||||
limit = int(obj.StackLimit + s.Locals)
|
||||
if haslinkregister() {
|
||||
limit += Thearch.Regsize
|
||||
}
|
||||
break // there can be only one
|
||||
}
|
||||
|
||||
// Walk through sp adjustments in function, consuming relocs.
|
||||
@ -1628,11 +1607,6 @@ func stkcheck(up *Chain, depth int) int {
|
||||
switch r.Type {
|
||||
// Direct call.
|
||||
case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER:
|
||||
// We handled calls to morestack already.
|
||||
if strings.HasPrefix(r.Sym.Name, "runtime.morestack") {
|
||||
continue
|
||||
}
|
||||
|
||||
ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
|
||||
ch.sym = r.Sym
|
||||
if stkcheck(&ch, depth+1) < 0 {
|
||||
@ -1670,6 +1644,9 @@ func stkprint(ch *Chain, limit int) {
|
||||
|
||||
if ch.sym != nil {
|
||||
name = ch.sym.Name
|
||||
if ch.sym.Nosplit != 0 {
|
||||
name += " (nosplit)"
|
||||
}
|
||||
} else {
|
||||
name = "function pointer"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user