1
0
mirror of https://github.com/golang/go synced 2024-11-23 00:30:07 -07:00

cmd/compile: better integrate parameter tagging with escape.go

This CL moves parameter tagging to before escape analysis is complete,
so we still have access to EscLocation. This will be useful once
EscLocation starts tracking higher-fidelity escape details.

Notably, this CL stops using n.Esc to record parameter escape analysis
details. Now escape analysis only ever sets n.Esc to EscNone or
EscHeap. (It still defaults to EscUnknown, and is set to EscNever in
some places though.)

Passes toolstash-check.

Updates #33981.

Change-Id: I50a91ea1e38c442092de6cd14e20b211f8f818c9
Reviewed-on: https://go-review.googlesource.com/c/go/+/193178
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Matthew Dempsky 2019-09-04 15:16:25 -07:00
parent 68a6536848
commit b9704872d1
3 changed files with 49 additions and 46 deletions

View File

@ -405,19 +405,7 @@ const unsafeUintptrTag = "unsafe-uintptr"
// marked go:uintptrescapes. // marked go:uintptrescapes.
const uintptrEscapesTag = "uintptr-escapes" const uintptrEscapesTag = "uintptr-escapes"
func esctag(fn *Node) { func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
fn.Esc = EscFuncTagged
narg := 0
for _, fs := range types.RecvsParams {
for _, f := range fs(fn.Type).Fields().Slice() {
narg++
f.Note = escparamtag(fn, narg, f)
}
}
}
func escparamtag(fn *Node, narg int, f *types.Field) string {
name := func() string { name := func() string {
if f.Sym != nil { if f.Sym != nil {
return f.Sym.Name return f.Sym.Name
@ -446,8 +434,15 @@ func escparamtag(fn *Node, narg int, f *types.Field) string {
// External functions are assumed unsafe, unless // External functions are assumed unsafe, unless
// //go:noescape is given before the declaration. // //go:noescape is given before the declaration.
if fn.Noescape() { if fn.Noescape() {
if Debug['m'] != 0 && f.Sym != nil {
Warnl(fn.Pos, "%S %v does not escape", funcSym(fn), name())
}
return mktag(EscNone) return mktag(EscNone)
} }
if Debug['m'] != 0 && f.Sym != nil {
Warnl(fn.Pos, "leaking param: %v", name())
}
return mktag(EscHeap) return mktag(EscHeap)
} }
@ -477,5 +472,26 @@ func escparamtag(fn *Node, narg int, f *types.Field) string {
} }
n := asNode(f.Nname) n := asNode(f.Nname)
return mktag(int(n.Esc)) loc := e.oldLoc(n)
esc := finalizeEsc(loc.paramEsc)
if Debug['m'] != 0 && !loc.escapes {
if esc == EscNone {
Warnl(n.Pos, "%S %S does not escape", funcSym(fn), n)
} else if esc == EscHeap {
Warnl(n.Pos, "leaking param: %S", n)
} else {
if esc&EscContentEscapes != 0 {
Warnl(n.Pos, "leaking param content: %S", n)
}
for i := 0; i < numEscReturns; i++ {
if x := getEscReturn(esc, i); x >= 0 {
res := n.Name.Curfn.Type.Results().Field(i).Sym
Warnl(n.Pos, "leaking param: %S to result %v level=%d", n, res, x)
}
}
}
}
return mktag(int(esc))
} }

View File

@ -147,12 +147,7 @@ func escapeFuncs(fns []*Node, recursive bool) {
e.curfn = nil e.curfn = nil
e.walkAll() e.walkAll()
e.finish() e.finish(fns)
// Record parameter tags for package export data.
for _, fn := range fns {
esctag(fn)
}
} }
func (e *Escape) initFunc(fn *Node) { func (e *Escape) initFunc(fn *Node) {
@ -1258,7 +1253,20 @@ func (l *EscLocation) leakTo(sink *EscLocation, derefs int) {
} }
} }
func (e *Escape) finish() { func (e *Escape) finish(fns []*Node) {
// Record parameter tags for package export data.
for _, fn := range fns {
fn.Esc = EscFuncTagged
narg := 0
for _, fs := range types.RecvsParams {
for _, f := range fs(fn.Type).Fields().Slice() {
narg++
f.Note = e.paramTag(fn, narg, f)
}
}
}
for _, loc := range e.allLocs { for _, loc := range e.allLocs {
n := loc.n n := loc.n
if n == nil { if n == nil {
@ -1279,27 +1287,10 @@ func (e *Escape) finish() {
} }
n.Esc = EscHeap n.Esc = EscHeap
addrescapes(n) addrescapes(n)
} else if loc.isName(PPARAM) { } else {
n.Esc = finalizeEsc(loc.paramEsc) if Debug['m'] != 0 && n.Op != ONAME && n.Op != OTYPESW && n.Op != ORANGE && n.Op != ODEFER {
if Debug['m'] != 0 && types.Haspointers(n.Type) {
if n.Esc == EscNone {
Warnl(n.Pos, "%S %S does not escape", funcSym(loc.curfn), n) Warnl(n.Pos, "%S %S does not escape", funcSym(loc.curfn), n)
} else if n.Esc == EscHeap {
Warnl(n.Pos, "leaking param: %S", n)
} else {
if n.Esc&EscContentEscapes != 0 {
Warnl(n.Pos, "leaking param content: %S", n)
} }
for i := 0; i < numEscReturns; i++ {
if x := getEscReturn(n.Esc, i); x >= 0 {
res := n.Name.Curfn.Type.Results().Field(i).Sym
Warnl(n.Pos, "leaking param: %S to result %v level=%d", n, res, x)
}
}
}
}
} else {
n.Esc = EscNone n.Esc = EscNone
if loc.transient { if loc.transient {
switch n.Op { switch n.Op {
@ -1307,10 +1298,6 @@ func (e *Escape) finish() {
n.SetNoescape(true) n.SetNoescape(true)
} }
} }
if Debug['m'] != 0 && n.Op != ONAME && n.Op != OTYPESW && n.Op != ORANGE && n.Op != ODEFER {
Warnl(n.Pos, "%S %S does not escape", funcSym(loc.curfn), n)
}
} }
} }
} }

View File

@ -18,7 +18,7 @@ func F1(a uintptr) {} // ERROR "escaping uintptr"
//go:uintptrescapes //go:uintptrescapes
//go:noinline //go:noinline
func F2(a ...uintptr) {} // ERROR "escaping ...uintptr" "a does not escape" func F2(a ...uintptr) {} // ERROR "escaping ...uintptr"
//go:uintptrescapes //go:uintptrescapes
//go:noinline //go:noinline