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 
>> <golan...@googlegroups.com> 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 <ia...@golang.org> 
>> >> wrote: 
>> >> > 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 
>> > 
>> > -- 
>> > 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 golang-nuts...@googlegroups.com. 
>> > 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 golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to