One of the difficulties of unsafe.Pointer is that if a package gets a value of type unsafe.Pointer then it can convert that pointer to other pointer types, or uintptr. This is true even if the package does not itself import "unsafe", but gets the unsafe.Pointer value by calling some other package. This is the reason that reflect.Value.Pointer returns uintptr rather than unsafe.Pointer.
For Go 2 I propose that we change the language to say that values of type unsafe.Pointer only have their special properties in packages that explicitly import "unsafe". If a package does not import "unsafe", then a value of type unsafe.Pointer may not be converted to other type.
If we make that change, then, Go 1 compatibility rules aside, we can safely permit reflect.Value.Pointer to return unsafe.Pointer.
Presumably this will also let us redefine reflect.StringHeader and reflect.SliceHeader to use unsafe.Pointer instead of uintptr.
I like this one.
Under this proposal, in order to determine whether a conversion expression T(x) may be an unsafe.Pointer conversion, the reader still needs to know three things that may not be locally obvious:
T is an alias for unsafe.Pointer, andunsafe.(1) and (2) may be arbitrarily distant in the code (even across package boundaries); (3) is fairly easy to find within the source file, but still requires the reader to jump from the current context to the import block and back.
In contrast, with a function-based unsafe API (such as the one @griesemer and I discussed in #20171), I believe all of that information could be present within the conversion expression itself.
(I do agree that this proposal is a strict improvement over the status quo, but in the space of “fixes for unsafe.Pointer” it seems like the low-cost/low-benefit solution. I wonder whether we could get a much larger benefit for an only marginally higher cost.)
If we make that change, then, Go 1 compatibility rules aside, we can safely permit reflect.Value.Pointer to return unsafe.Pointer.
I don't find this argument compelling. I think we can safely permit reflect.Value.Pointer to return unsafe.Pointer today anyway (again, Go 1 compatibility rules aside).
The Go toolchain no longer supports "safe" mode, so there's no builtin functionality that restricts access to package unsafe. So this argument is implicitly assuming some external safety-validation tool that restricts access to package unsafe.
But then I don't see any reason such an external tool can't just look for unsafe.Pointer->*T conversions in addition to disallowing import "unsafe". That's really no different than what cmd/compile, gccgo, and go/types would all be required to do anyway.
I think a security-oriented subset of Go a la Joe-E or Caja would be fun to work on, but I don't think trying to one-off tackle individual issues is going to get us there. (I also suspect compiling to wasm is a more pragmatic solution to this problem.)
That said, we already tie other unsafe features like //go:linkname to import "unsafe", so it's not like this is without precedent.
So overall I'd say I'm weakly opposed.
Note that reflect.NewAt allows converting unsafe.Pointer values to any pointer type even without compiler magic: https://play.golang.org/p/w-6sabmpnz9
@mdempsky's comment does seem like a show-stopper: there's not much point in taking away tp := (*T)(u) if you can still write tp := reflect.NewAt(reflect.TypeOf((*T)(nil)), u).Interface().(*T) instead.
So probably this proposal should be declined.
Now that there are no longer any environments penalizing unsafe (in particular, App Engine does not reject unsafe anymore), we could add reflect.Value.UnsafePointer returning unsafe.Pointer.
Retracting.
Most helpful comment
Presumably this will also let us redefine
reflect.StringHeaderandreflect.SliceHeaderto useunsafe.Pointerinstead ofuintptr.