'why the below two code cause escape in golang

I'm investigating the golang's escape analysis, but in the post http://npat-efault.github.io/programming/2016/10/10/escape-analysis-and-interfaces.html, I have two points of confusion:

Code one:

func Ok(f os.File) []byte {
    var x [128]byte
    b := x[:]
    n, _ := f.Read(b)
    r := make([]byte, n)
    copy(r, b[:n])
    return r
}

func NotOk(c net.Conn) []byte {
    var x [128]byte
    b := x[:]
    n, _ := c.Read(b)
    r := make([]byte, n)
    copy(r, b[:n])
    return r
}

go build -gcflags "-m -l" part3_escape.go

The output:

# command-line-arguments
./part3_escape.go:64:9: leaking param: f
./part3_escape.go:68:11: make([]byte, n) escapes to heap
./part3_escape.go:73:12: leaking param: c
./part3_escape.go:74:6: moved to heap: x
./part3_escape.go:77:11: make([]byte, n) escapes to heap
# command-line-arguments
runtime.main_main·f: function main is undeclared in the main package

I do not know why x escape (moved to heap: x)

Code two:

type S struct {
    s1 int
}

func (s *S) M1(i int) { s.s1 = i }

type I interface {
    M1(int)
}

func g() {
    var s1 S  // this escapes
    var s2 S  // this does not
        
    f1(&s1)
    f2(&s2)
}

func f1(s I) { s.M1(42) }
func f2(s *S) { s.M1(42) }

go build -gcflags "-m -l" part3_escape.go

The output:

# command-line-arguments
./part3_escape.go:63:7: s does not escape
./part3_escape.go:77:9: leaking param: s
./part3_escape.go:78:9: s does not escape
./part3_escape.go:70:6: moved to heap: s1
<autogenerated>:1: leaking param: .this
# command-line-arguments
runtime.main_main·f: function main is undeclared in the main package

I do not know why s1 escape (moved to heap: s1)

It would be great if someone could help explain it,thx😄



Solution 1:[1]

The compiler is unable to prove that a call through the interface doesn't store a pointer somewhere. There may be a potential implementation of the interface that stores a pointer, hence it must assume the values can escape.

Newer Go versions can devirtualise calls when inlining and potentially avoid values escaping. You will see this when removing the -l flag in your second example.

There is some discussion on https://github.com/golang/go/issues/33160.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1