-
Notifications
You must be signed in to change notification settings - Fork 18.9k
Description
What version of Go are you using (go version)?
1.12, but N/A
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env)?
N/A
What did you do?
Read the documentation for unsafe.
What did you expect to see?
Something that did not confuse me.
What did you see instead?
Something that confused me.
In general,
reflect.SliceHeader andreflect.StringHeadershould be used only as*reflect.SliceHeaderand*reflect.StringHeaderpointing at actual slices or strings, never as plain structs. A program should not declare or allocate variables of these struct types.
This has an accompanying example:
// INVALID: a directly-declared header will not hold Data as a reference.
var hdr reflect.StringHeader
hdr.Data = uintptr(unsafe.Pointer(p))
hdr.Len = n
s := *(*string)(unsafe.Pointer(&hdr)) // p possibly already lost
What's not obvious to me: Is the only reason this is "INVALID" that p might already be lost, such that a runtime.KeepAlive(p) after the last line would have saved it? Or is this also intended to cover the possibility that some future version of Go may have additional unspecified magic in a slice object which is not in the SliceHeader parts, such that simply creating a SliceHeader (or a StringHeader) doesn't actually make a thing which could be a valid object?
I've been writing code which has a pointer (which is persistent, and in a data structure which survives past the current scope, thus at no risk of being garbage collected), and which does something to the effect of:
asUint16 := *(*[]uint16)(unsafe.Pointer(&reflect.SliceHeader{Data: uintptr(unsafe.Pointer(obj.ptr)), Len: int(obj.len), Cap: int(obj.len)}))
In fact, obj.ptr isn't going away, so I'm not worried about garbage collection. But if an actual Slice were not exactly the same size as a SliceHeader, but rather, the SliceHeader were just a prefix of the actual internal slice representation... This code would in fact be just plain wrong, because other code might try to access the "rest" of the slice object, and not find it.
Instead, I'd need to do something like:
var u []uint16
h := (*reflect.SliceHeader)&u
h.Data, h.Len, h.Cap = uintptr(obj.ptr), obj.len, obj.len
Which is, I suppose, certainly no harder to read, but I'm not sure whether it offers any semantic difference, apart from u holding the reference to the pointer, in a way that a temporary slice header object wouldn't.