Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: Pointer escapes when stored in a non-escaping map #63343

Closed
myaaaaaaaaa opened this issue Oct 3, 2023 · 2 comments
Closed

cmd/compile: Pointer escapes when stored in a non-escaping map #63343

myaaaaaaaaa opened this issue Oct 3, 2023 · 2 comments

Comments

@myaaaaaaaaa
Copy link

What version of Go are you using (go version)?

$ go version
go version go1.21.1 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.1'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='0'
GOMOD='/dev/null'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build93415193=/tmp/go-build -gno-record-gcc-switches'

What did you do?

Compiled this program with go build -gcflags="-m"

package main

func noescape_ptr() {
	i := new(int) //Does not escape
	*i = 5
}
func noescape_ptr_chain() {
	i := new(int) //Does not escape
	j := &i
	k := &j
	***k = 5
}
func noescape_slice() {
	i := new(int) //Does not escape
	s := []*int{i, i, i}
	*s[0] = 5
}
func escapes_map() {
	i := new(int) //Escapes :(
	m := map[int]*int{0: i} //but fortunately, this doesn't
	*m[0] = 5
}

func main() {
}

What did you expect to see?

 ./main.go:4:10: new(int) does not escape
 ./main.go:8:10: new(int) does not escape
 ./main.go:14:10: new(int) does not escape
 ./main.go:15:13: []*int{...} does not escape
+./main.go:19:10: new(int) does not escape
 ./main.go:20:19: map[int]*int{...} does not escape

What did you see instead?

 ./main.go:4:10: new(int) does not escape
 ./main.go:8:10: new(int) does not escape
 ./main.go:14:10: new(int) does not escape
 ./main.go:15:13: []*int{...} does not escape
-./main.go:19:10: new(int) escapes to heap
 ./main.go:20:19: map[int]*int{...} does not escape
@randall77
Copy link
Contributor

This is unfortunately working as intended.
Maps are fundamentally a heap-based data structure. Due to the possibility of map growth (which requires heap allocation), all the keys and values must escape even if the map doesn't.
Conceivably we could detect non-escaping maps with known bounded numbers of inserts that would guarantee no growth, but that's probably a pretty small set.

@myaaaaaaaaa
Copy link
Author

Now that you mention it, the comparison I made with slices was incorrect. Here, the pointer escapes from both the slice and map:

package main

func escape_slice() {
	i := new(int) //Escapes
	s := []*int{}
	s = append(s, i)
}
func escapes_map() {
	i := new(int) //Escapes
	m := map[int]*int{}
	m[0] = i
}

func main() {
}

I'll close this now since this bug report was motivated by a supposed gap in functionality between slices and maps. Thanks for the feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants