That is a worry, but escape analysis can handle this case. It understands
flow of pointers through unsafe.Pointer and uintptr. As a consequence, in
this example it forces the array to be allocated on the heap.
The runtime has on occasion a need to hide values from escape analysis. It
has to do some weird math on the uintptr to hide the escape. It uses:
// noescape hides a pointer from escape analysis. noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input. noescape is inlined and currently
// compiles down to zero instructions.
// USE CAREFULLY!
//go:nosplit
func noescape(p unsafe.Pointer) unsafe.Pointer {
x := uintptr(p)
return unsafe.Pointer(x ^ 0)
}
On Friday, March 24, 2017 at 11:58:31 AM UTC-7, Jerome Froelich wrote:
>
> It just occurred to me that there may actually be a problem with the
> conversion functions in the example. Specifically, since the Go
> compiler can allocate byte slices on the heap if they do not escape, the
> following function may be invalid:
>
> func foo() string {
> v := []uint64{1,2,3}
> s := sliceToStringUnsafe(v)
> return s
> }
>
> Admittedly, this is a contrived example but I think it can illustrate the
> issue. As noted on this previous thread
> <https://groups.google.com/forum/#!topic/golang-nuts/KdbtOqNK6JQ> the
> compiler will allocate slices on the heap if it can prove they do not
> escape. Consequently, in the function above, the data for v can be
> allocated on the stack. In such a case, since sliceToStringUnsafe only
> adjusts pointers, the string it returns will point to this stack-allocated
> data. However, once foo returns, this data is no longer valid and can be
> overwritten by subsequent functions that are pushed on the stack.
>
> On Thursday, March 23, 2017 at 9:05:48 PM UTC-4, Caleb Spare wrote:
>>
>> Filed: https://github.com/golang/go/issues/19687
>>
>> On Thu, Mar 23, 2017 at 4:41 PM, 'Keith Randall' via golang-nuts
>> <[email protected]> wrote:
>> >
>> >
>> > On Thursday, March 23, 2017 at 4:24:40 PM UTC-7, Caleb Spare wrote:
>> >>
>> >> That's very good to know. Thanks, Ian.
>> >>
>> >> Unfortunately if I use this KeepAlive-based fix, p escapes and so the
>> >> function now allocates. I guess I'll stick with the original version
>> >> from my first email.
>> >>
>> >> Does this indicate a shortcoming of either compiler support for
>> >> KeepAlive or escape analysis in general?
>> >>
>> >
>> > KeepAlive shouldn't be making things escape. If that is happening you
>> > should file a bug for it.
>> > The definition is:
>> >
>> > //go:noinline
>> > func KeepAlive(interface{}) {}
>> >
>> > which should be pretty easy to analyze :)
>> >
>> >> Caleb
>> >>
>> >> On Thu, Mar 23, 2017 at 10:26 AM, Ian Lance Taylor <[email protected]>
>> >> wrote:
>> >> > On Thu, Mar 23, 2017 at 9:16 AM, Caleb Spare <[email protected]>
>> 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
>> >
>> > --
>> > You received this message because you are subscribed to the Google
>> Groups
>> > "golang-nuts" group.
>> > To unsubscribe from this group and stop receiving emails from it, send
>> an
>> > email to [email protected].
>> > For more options, visit https://groups.google.com/d/optout.
>>
>
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.