-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: Go 2: reflect: return opaque pointer instead of uintptr #24654
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
As just a first example I can recall: This will close the only legal way how to pass a static (Go text segment allocated) Go string to code automatically translated from C to use as its text segment without copying. Similar problems arise for the |
@cznic, could you elaborate? It seems like you could add one more method to @dsnet's proposal to cover that use-case, while still addressing his concerns about That method would be a simple setter: func (p *Pointer) Set(v unsafe.Pointer) {
p.p = v
} |
The discussed // TS allocates the R/O text segment of a package/command.
func TS(init string) uintptr { return (*reflect.StringHeader)(unsafe.Pointer(&init)).Data } For #include <stdio.h>
int main() {
printf("Hello World\n");
} The translated Go code is currently package main
import (
"os"
"unsafe"
"github.com/cznic/crt"
)
var _ unsafe.Pointer
const null = uintptr(0)
func main() {
psz := unsafe.Sizeof(uintptr(0))
argv := crt.MustCalloc((len(os.Args) + 1) * int(psz))
p := argv
for _, v := range os.Args {
*(*uintptr)(unsafe.Pointer(p)) = crt.CString(v)
p += psz
}
a := os.Environ()
env := crt.MustCalloc((len(a) + 1) * int(psz))
p = env
for _, v := range a {
*(*uintptr)(unsafe.Pointer(p)) = crt.CString(v)
p += psz
}
*(*uintptr)(unsafe.Pointer(Xenviron)) = env
X_start(crt.NewTLS(), int32(len(os.Args)), argv)
}
// X_start is defined at crt0.c:7:6
func X_start(tls crt.TLS, _argc int32, _argv uintptr /* **int8 */) {
crt.X__register_stdfiles(tls, Xstdin, Xstdout, Xstderr, Xenviron)
crt.X__builtin_exit(tls, Xmain(tls, _argc, _argv))
}
// Xstdin *void, escapes: false, crt0.c:5:6
var Xstdin = X__stdfiles
// Xstdout *void, escapes: false, crt0.c:5:31
var Xstdout = X__stdfiles + 8
// Xstderr *void, escapes: false, crt0.c:5:57
var Xstderr = X__stdfiles + 16
// Xenviron **int8, escapes: true, crt0.c:4:6
var Xenviron = bss
// Xmain is defined at hello.c:3:5
func Xmain(tls crt.TLS, _ int32, _ uintptr /* **int8 */) (r int32) {
crt.Xprintf(tls, ts /* "Hello World\n" */)
return r
}
// X__stdfiles [3]uintptr, escapes: true, crt0.c:3:15
var X__stdfiles = bss + 8
var (
bss = crt.BSS(&bssInit[0])
bssInit [32]byte
ts = crt.TS("Hello World\n\x00")
) So a setter is not what's needed. |
FTR: Examples above apply to the |
Oh, I think I see. Under this proposal, that code would end up like: func TS(init string) (p unsafe.Pointer) {
h := (*reflect.StringHeader)(unsafe.Pointer(&init))
h.Data.SetInto(&p)
return p
} // Xmain is defined at hello.c:3:5
func Xmain(tls crt.TLS, _ int32, _ uintptr /* **int8 */) (r int32) {
crt.Xprintf(tls, uintptr(ts) /* "Hello World\n" */)
return r
} and the rest of the code would remain unchanged. (Am I missing |
Almost, except for the different signature. The PS: Hmm, it seems I've misread the |
@cznic You may be interested in the |
Thanks @ianlancetaylor, however in this particular case of |
See also #19367. |
Instead of introducing another representation for an unsafe.Pointer, we could instead use an unsafe.Pointer directly together with the property that an unsafe.Pointer can only be used in a conversion if the unsafe package is imported (as proposed in #26070). |
I'm rescinding this proposal in light of #40592. |
The
Value.Pointer
andValue.UnsafeAddr
methods and theSliceHeader.Data
andStringHeader.Data
fields all useuintptr
. This has some downsides:unsafe
to special-case conversions:reflect.DeepEqual
implementation importsunsafe
in order to convert theuintptr
to anunsafe.Pointer
to have a pointer that the GC knows how to scan (or move if we ever have a moving GC).In Go2, I propose that
Value.UnsafeAddr
andValue.Pointer
methods return and theSliceHeader.Data
andStringHeader.Data
fields be areflect.Pointer
type:The
SetInto
method writes the pointer into p2 and requires the user to already have importedunsafe
. It's a more clunky, but less error prone.Alternatively, we could define
unsafe.OpaquePointer
that is safe to store and pass around, but does not permit arithmetic on it, nor can it be converted to a pointer of any arbitrary type. You can convertunsafe.OpaquePointer
tounsafe.Pointer
and vice versa. However, you cannot convert anuintptr
to anunsafe.OpaquePointer
as this would easily allow the creation of invalid pointers. This simplifies the warnings aboutuintptr
not being stored in a variable, and must be within the same expression. To ensure usage ofOpaquePointer
does not requireunsafe
, we could type alias it from thereflect
package.Thus, rules 5 and 6 in
unsafe
can be entirely eliminated.The text was updated successfully, but these errors were encountered: