Skip to content

Commit 35e6a10

Browse files
cherrymuiianlancetaylor
authored andcommitted
[release-branch.go1.12] cmd/compile: flow interface data to heap if CONVIFACE of a non-direct interface escapes
Consider the following code: func f(x []*T) interface{} { return x } It returns an interface that holds a heap copy of x (by calling convT2I or friend), therefore x escape to heap. The current escape analysis only recognizes that x flows to the result. This is not sufficient, since if the result does not escape, x's content may be stack allocated and this will result a heap-to-stack pointer, which is bad. Fix this by realizing that if a CONVIFACE escapes and we're converting from a non-direct interface type, the data needs to escape to heap. Running "toolstash -cmp" on std & cmd, the generated machine code are identical for all packages. However, the export data (escape tags) differ in the following packages. It looks to me that all are similar to the "f" above, where the parameter should escape to heap. io/ioutil/ioutil.go:118 old: leaking param: r to result ~r1 level=0 new: leaking param: r image/image.go:943 old: leaking param: p to result ~r0 level=1 new: leaking param content: p net/url/url.go:200 old: leaking param: s to result ~r2 level=0 new: leaking param: s (as a consequence) net/url/url.go:183 old: leaking param: s to result ~r1 level=0 new: leaking param: s net/url/url.go:194 old: leaking param: s to result ~r1 level=0 new: leaking param: s net/url/url.go:699 old: leaking param: u to result ~r0 level=1 new: leaking param: u net/url/url.go:775 old: (*URL).String u does not escape new: leaking param content: u net/url/url.go:1038 old: leaking param: u to result ~r0 level=1 new: leaking param: u net/url/url.go:1099 old: (*URL).MarshalBinary u does not escape new: leaking param content: u flag/flag.go:235 old: leaking param: s to result ~r0 level=1 new: leaking param content: s go/scanner/errors.go:105 old: leaking param: p to result ~r0 level=0 new: leaking param: p database/sql/sql.go:204 old: leaking param: ns to result ~r0 level=0 new: leaking param: ns go/constant/value.go:303 old: leaking param: re to result ~r2 level=0, leaking param: im to result ~r2 level=0 new: leaking param: re, leaking param: im go/constant/value.go:846 old: leaking param: x to result ~r1 level=0 new: leaking param: x encoding/xml/xml.go:518 old: leaking param: d to result ~r1 level=2 new: leaking param content: d encoding/xml/xml.go:122 old: leaking param: leaking param: t to result ~r1 level=0 new: leaking param: t crypto/x509/verify.go:506 old: leaking param: c to result ~r8 level=0 new: leaking param: c crypto/x509/verify.go:563 old: leaking param: c to result ~r3 level=0, leaking param content: c new: leaking param: c crypto/x509/verify.go:615 old: (nothing) new: leaking closure reference c crypto/x509/verify.go:996 old: leaking param: c to result ~r1 level=0, leaking param content: c new: leaking param: c net/http/filetransport.go:30 old: leaking param: fs to result ~r1 level=0 new: leaking param: fs net/http/h2_bundle.go:2684 old: leaking param: mh to result ~r0 level=2 new: leaking param content: mh net/http/h2_bundle.go:7352 old: http2checkConnHeaders req does not escape new: leaking param content: req net/http/pprof/pprof.go:221 old: leaking param: name to result ~r1 level=0 new: leaking param: name cmd/internal/bio/must.go:21 old: leaking param: w to result ~r1 level=0 new: leaking param: w Fixes #29353. Change-Id: I7e7798ae773728028b0dcae5bccb3ada51189c68 Reviewed-on: https://go-review.googlesource.com/c/162829 Run-TryBot: Cherry Zhang <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> Reviewed-by: David Chase <[email protected]> (cherry picked from commit 0349f29) Reviewed-on: https://go-review.googlesource.com/c/163203 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 320da8d commit 35e6a10

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

src/cmd/compile/internal/gc/esc.go

+10
Original file line numberDiff line numberDiff line change
@@ -2105,6 +2105,16 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
21052105
step.describe(src)
21062106
}
21072107
extraloopdepth = modSrcLoopdepth
2108+
if src.Op == OCONVIFACE {
2109+
lt := src.Left.Type
2110+
if !lt.IsInterface() && !isdirectiface(lt) && types.Haspointers(lt) {
2111+
// We're converting from a non-direct interface type.
2112+
// The interface will hold a heap copy of the data
2113+
// (by calling convT2I or friend). Flow the data to heap.
2114+
// See issue 29353.
2115+
e.escwalk(level, &e.theSink, src.Left, e.stepWalk(dst, src.Left, "interface-converted", step))
2116+
}
2117+
}
21082118
}
21092119

21102120
case ODOT,

test/escape_because.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func f2(q *int) { // ERROR "from &u \(address-of\) at escape_because.go:43$" "fr
4343
sink = &u // ERROR "&u escapes to heap$" "from &u \(interface-converted\) at escape_because.go:43$" "from sink \(assigned to top level variable\) at escape_because.go:43$"
4444
}
4545

46-
func f3(r *int) interface{} { // ERROR "from \[\]\*int literal \(slice-literal-element\) at escape_because.go:47$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$" "leaking param: r to result ~r1 level=-1$"
46+
func f3(r *int) interface{} { // ERROR "from \[\]\*int literal \(slice-literal-element\) at escape_because.go:47$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$" "leaking param: r"
4747
c := []*int{r} // ERROR "\[\]\*int literal escapes to heap$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$"
4848
return c // "return" // ERROR "c escapes to heap$" "from ~r1 \(return\) at escape_because.go:48$"
4949
}

test/escape_param.go

+15
Original file line numberDiff line numberDiff line change
@@ -424,3 +424,18 @@ func h(x *Node) { // ERROR "leaking param: x"
424424
Sink = g(y)
425425
f(y)
426426
}
427+
428+
// interface(in) -> out
429+
// See also issue 29353.
430+
431+
// Convert to a non-direct interface, require an allocation and
432+
// copy x to heap (not to result).
433+
func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$"
434+
return x // ERROR "x escapes to heap"
435+
}
436+
437+
// Convert to a direct interface, does not need an allocation.
438+
// So x only leaks to result.
439+
func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r1 level=0"
440+
return x // ERROR "x escapes to heap"
441+
}

0 commit comments

Comments
 (0)