Skip to content

Commit

Permalink
cmd/compile: print accurate escape reason for non-const-length slices
Browse files Browse the repository at this point in the history
This change makes `-m -m` print a better explanation for the case
where a slice is marked as escaping and heap-allocated because it
has a non-constant len/cap.

Fixes #24578

Change-Id: I0ebafb77c758a99857d72b365817bdba7b446cc0
Reviewed-on: https://go-review.googlesource.com/102895
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Ilya Tocar <ilya.tocar@intel.com>
  • Loading branch information
ALTree committed Mar 28, 2018
1 parent f8b28e2 commit 360c191
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 4 deletions.
19 changes: 15 additions & 4 deletions src/cmd/compile/internal/gc/esc.go
Original file line number Diff line number Diff line change
Expand Up @@ -665,18 +665,29 @@ func (e *EscState) esc(n *Node, parent *Node) {
}
}

// Big stuff escapes unconditionally
// "Big" conditions that were scattered around in walk have been gathered here
// Big stuff and non-constant-sized stuff escapes unconditionally.
// "Big" conditions that were scattered around in walk have been
// gathered here.
if n.Esc != EscHeap && n.Type != nil &&
(n.Type.Width > maxStackVarSize ||
(n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 ||
n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {

// isSmallMakeSlice returns false for non-constant len/cap.
// If that's the case, print a more accurate escape reason.
var msgVerb, escapeMsg string
if n.Op == OMAKESLICE && (!Isconst(n.Left, CTINT) || !Isconst(n.Right, CTINT)) {
msgVerb, escapeMsg = "has ", "non-constant size"
} else {
msgVerb, escapeMsg = "is ", "too large for stack"
}

if Debug['m'] > 2 {
Warnl(n.Pos, "%v is too large for stack", n)
Warnl(n.Pos, "%v "+msgVerb+escapeMsg, n)
}
n.Esc = EscHeap
addrescapes(n)
e.escassignSinkWhy(n, n, "too large for stack") // TODO category: tooLarge
e.escassignSinkWhy(n, n, escapeMsg) // TODO category: tooLarge
}

e.esc(n.Left, n)
Expand Down
7 changes: 7 additions & 0 deletions test/escape_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,10 @@ func doesMakeSlice(x *string, y *string) { // ERROR "leaking param: x" "leaking
b := make([]*string, 65537) // ERROR "make\(\[\]\*string, 65537\) escapes to heap"
b[0] = y
}

func nonconstArray() {
n := 32
s1 := make([]int, n) // ERROR "make\(\[\]int, n\) escapes to heap"
s2 := make([]int, 0, n) // ERROR "make\(\[\]int, 0, n\) escapes to heap"
_, _ = s1, s2
}
7 changes: 7 additions & 0 deletions test/escape_because.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ func transmit(b []byte) []byte { // ERROR "from ~r1 \(return\) at escape_because
return b
}

func f14() {
n := 32
s1 := make([]int, n) // ERROR "make\(\[\]int, n\) escapes to heap" "from make\(\[\]int, n\) \(non-constant size\)"
s2 := make([]int, 0, n) // ERROR "make\(\[\]int, 0, n\) escapes to heap" "from make\(\[\]int, 0, n\) \(non-constant size\)"
_, _ = s1, s2
}

// The list below is all of the why-escapes messages seen building the escape analysis tests.
/*
for i in escape*go ; do echo compile $i; go build -gcflags '-l -m -m' $i >& `basename $i .go`.log ; done
Expand Down

0 comments on commit 360c191

Please sign in to comment.