On Thu, Mar 23, 2017 at 9:16 AM, Caleb Spare <
ces...@gmail.com> wrote:
>
> Brief follow-up: does the seeming validity of the code rely at all on
> the fact that the indicated line is written as a single line? What if,
> instead, a *StringHeader var were extracted?
>
> func stringToSliceUnsafe(s string) []uint64 {
> var v []uint64
> h := (*reflect.StringHeader)(unsafe.Pointer(&s)) // <--
> sh := (*reflect.SliceHeader)(unsafe.Pointer(&v))
> sh.Data = h.Data
> sh.Len = h.Len >> 3
> sh.Cap = h.Len >> 3
> return v
> }
>
> (Play link:
https://play.golang.org/p/BmGtYTsGNY)
>
> Does h keep s alive? A strict reading of rule 6 doesn't seem to say
> that keeping a *StringHeader or *SliceHeader around keeps the
> underlying string/slice alive (but it's sort of implied by the rule 6
> example code, which doesn't refer to s after converting it to a
> *StringHeader).
That is an interesting point. I don't think there is anything keeping
s alive here. I think this isn't quite the same as the example in the
docs, because that example is assuming that you are doing to use s
after setting the fields--why else would you be doing that? In this
case it does seem theoretically possible that s could be freed between
the assignment to h and the use of h.Data. With the current and
foreseeable toolchains it's a purely theoretical problem, since there
is no point there where the goroutine could be preempted and the fact
that s is no longer referenced be detected. But as a theoretical
problem it does seem real. One fix would be something like
p := &s
h := (*reflect.StringHeader)(unsafe.Pointer(p))
sh := (*reflect.SliceHeader)(unsafe.Pointer(&v))
sh.Data = h.Data
sh.Len = ...
sh.Cap = ...
runtime.KeepAlive(p)
Ian