I first asked this on https://reddit.com/r/golang but the contribution guide on github recommends this forum, so I'll post here before finally raising an issue on github if this appears to be a real bug.
ORIGINAL POST:
I came across this issue in some code I was reviewing today where a string is converted into a []byte and then a 32 byte slice is taken from that and returned. It returns a 32 byte slice even if the string is empty or less than 32 bytes in length as long as its not a string literal (comes from a function or stored in variable). I can index the slice normally and iterate over its elements, but attempting to print it with fmt.Printf causes a runtime error where it realizes the capacity is not actually 32. Trying to get a slice larger than 32 fails though smaller slices are okay. I think that has something to do with the storage needed to describe a slice 8 bytes for memory location, 8 bytes for size, 8 bytes for capacity, 8 for padding as explained here: https://stackoverflow.com/questions/67839752/why-does-an-empty-slice-have-24-bytes
Here's a playground demo: https://play.golang.com/p/yiLPvRYq8PJ
Maybe this is a known issue and or expected behavior so I thought I'd ask here before raising an issue on github.
I believe this is working as intended, because I don't think the spec makes any guarantees about the capacity of the slice you get back from a conversion.
On 27/07/2023 03:48, Kyle Harrity wrote:
> Maybe this is a known issue and or expected behavior so I thought I'd
> ask here before raising an issue on github.
>
I think I know what's going on, the compiler inlined getStrBytes and can
prove "k" is short enough to put in the stack, then the runtime creates
the slice backed from an array on the stack, but never sets its
capacity, just length, so you're left with 32 bytes of capacity to
expand (see
https://go.googlesource.com/go/+/refs/tags/go1.20.6/src/runtime/string.go#170).
When you uncomment your print of k, then the compiler can't prove that
fmt.Printf won't keep the address of k, so it's not safe to store it on
the stack anymore, and you have the "expected behavior", an array
allocated from rawbyteslice which does set the capacity to len(s) (0 in
this case).