This is a proof-of-concept demonstration of a userland check for not-in-heap types.
$ go run pass/check.go -- pass/testdata/good.go
$ go run pass/check.go -- pass/testdata/bad.go
/home/mdempsky/wd/notinheap/pass/testdata/bad.go:9:25: heap allocation of x: new x (new)
/home/mdempsky/wd/notinheap/pass/testdata/bad.go:11:24: heap allocation of x: new x (complit)
/home/mdempsky/wd/notinheap/pass/testdata/bad.go:15:32: heap allocation of x: make []x n n
exit status 3
It relies on the buildssa analyzer pass, but in retrospect it could probably just as easily achieve the same result using just go/ast and go/types directly.
The interesting cases to detect are:
- Named parameters and variables of NIH type.
- Composite literals whose address is taken (e.g.,
&T{...}
). - Dynamic slice construction (e.g.,
make([]T, ...)
).
There are other cases where values can end up on the Go heap (e.g., map and channel backing stores, non-pointer-shaped values converted to interface type, large spilled temporaries), but none of these memory locations are user-addressable (i.e., users cannot construct a pointer to them).