Is unsafe.Pointer(reflect.Value.UnsafeAddr()) safe?

497 views
Skip to first unread message

Name No

unread,
Apr 17, 2021, 7:46:32 PM4/17/21
to golang-nuts

reflect.Value.UnsafeAddr has the commence attached like that:

//go:nocheckptr
// This prevents inlining Value.UnsafeAddr when -d=checkptr is enabled,
// which ensures cmd/compile can recognize unsafe.Pointer(v.UnsafeAddr())
// and make an exception.

Seems it is saying unsafe.Pointer(reflect.Value.UnsafeAddr())  is dangerous that go:nocheckptr can disable UnsafeAddr  from inline, so cmd/compile can detect it is a function call and raise an exception.

But indeed, the following code will not raise any exception at   ptr := unsafe.Pointer(rf.UnsafeAddr()). 
It indicates that unsafe.Pointer(rf.UnsafeAddr()) is safe.

Anybody can help to explain this?

go run -race -gcflags=all=-d=checkptr c.go
package main

import (
        "reflect"
        "unsafe"
        "fmt"
       )

func main() {
        var s = struct{ foo int }{100}

        rs := reflect.ValueOf(&s).Elem()
        rf := rs.Field(0)

       ptr := unsafe.Pointer(rf.UnsafeAddr())

        x := rf.UnsafeAddr()
       ptr = unsafe.Pointer(x)
       fmt.Println(ptr)
}

Axel Wagner

unread,
Apr 18, 2021, 5:19:22 AM4/18/21
to Name No, golang-nuts
Not "raise an exception", "make an exception". Go doesn't have exceptions, so the word "exception" here means "not do something you'd otherwise do" - namely "complain about the conversion of a uintptr to an unsafe.Pointer" :)

The exact rules for converting to and from unsafe.Pointer are here: https://golang.org/pkg/unsafe/#Pointer
Rule 5 is the relevant one - so, yes, this is safe.

--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/14da5c55-9137-46bc-90e1-b51b8ef6553bn%40googlegroups.com.

Cuong Manh Le

unread,
Apr 18, 2021, 3:18:35 PM4/18/21
to Name No, golang-nuts
What's your platform?

On M1, checkptr reports an error for me. The code:

ptr := unsafe.Pointer(rf.UnsafeAddr())

is safe, but:

x := rf.UnsafeAddr()
ptr = unsafe.Pointer(x)

is not.

Cuong Manh Le


Axel Wagner

unread,
Apr 18, 2021, 4:28:25 PM4/18/21
to Cuong Manh Le, Name No, golang-nuts
Again, the rules are very clear and in accordance with what's been said here (both by OP and by you):

(5) Conversion of the result of reflect.Value.Pointer or reflect.Value.UnsafeAddr from uintptr to Pointer. 
 
Package reflect's Value methods named Pointer and UnsafeAddr return type uintptr instead of unsafe.Pointer to keep callers from changing the result to an arbitrary type without first importing "unsafe". However, this means that the result is fragile and must be converted to Pointer immediately after making the call, in the same expression: 
 
p := (*int)(unsafe.Pointer(reflect.ValueOf(new(int)).Pointer())) 

As in the cases above, it is invalid to store the result before the conversion: 

// INVALID: uintptr cannot be stored in variable
// before conversion back to Pointer.
u := reflect.ValueOf(new(int)).Pointer()
p := (*int)(unsafe.Pointer(u))

The rules specifically call out one as safe and the other as invalid.

Name No

unread,
Apr 19, 2021, 5:55:45 AM4/19/21
to golang-nuts
Thanks.
I did misunderstand the 'exception'. 

Reply all
Reply to author
Forward
0 new messages