Thanks for your reply. I was really missing an essential piece. I found a bit weird that you need to write a helper to pass a uintptr to a void* C function. It could be nice to allow that
func Foo(x uintptr) { C.foo((*C.char)x) } but unfortunately, the compiler does not seem to accept it. Is there a reason ? Anyway, I suppose the issue is that the runtime will interpret the uintptr, when cast to a unsafe.Pointer as a potential valid pointer and if it looks a bit too much like a legit go pointer, that might confuse the GC. I suppose that unsafe.Pointer can safely handle C pointers (from the doc of cgo) If the uintptr contains a valid C pointer, do we have a practical issue, like with the following code ? func main() { v := uintptr(unsafe.Pointer(C.CString("Hello from stdio"))) C.myprint(unsafe.Pointer(v)) C.free(unsafe.Pointer(cs)) } This is a question about the current implementation, I know it violates the rule of unsafe.Pointer. This is just to have a better understanding about what the runtime does and when (at conversion time? C call time ? GC time ?) >From your last paragraph, can I do that ? /* #include <stdint.h> static void* IntToPtr(uintptr_t v) { return (void*)v; } */ import "C" import ( "runtime/cgo" "unsafe" ) func HandleAsPointer(h cgo.Handle) unsafe.Pointer { return C.IntToPtr(C.uintptr_t(uintptr(h))) } Here the cast int -> void* happens in the C world and the conversion back to unsafe.Pointer looks legit according to the rule of cgo. But this will create an unsafe.Pointer containing a totally invalid pointer. Will it work (practically and theoretically) ? Is the GC robust against the presence of a random value in an unsafe.Pointer ? Thanks On Wednesday, November 23, 2022 at 9:31:45 PM UTC+1 Ian Lance Taylor wrote: > On Wed, Nov 23, 2022 at 9:25 AM Frédéric De Jaeger > <fdej...@novaquark.com> wrote: > > > > There is something that puzzles me a lot in the doc about cgo.Handle > there https://pkg.go.dev/runtime/cgo. It says: > > > > Some C functions accept a void* argument that points to an arbitrary > data value supplied by the caller. It is not safe to coerce a cgo.Handle > (an integer) to a Go unsafe.Pointer, but instead we can pass the address of > the cgo.Handle to the void* parameter, as in this variant of the previous > example: > > > > I was under the impression that casting a uintptr to an unsafe.Pointer > just to call a C function (that accepts a void*) is somewhat valid. (This > is not clearly specified as a valid case in the doc of unsafe.Pointer, so, > it might be invalid from a very pedantic point of view). > > > > The advice given in the doc looks worst. Taking the address of a local > variable and giving it to C looks even more undefined (if C stores the > pointer and reuse it after the original call returns). > > > > Don't we have a doc issue there ? > > > > I know that in C, the conversion uintptr -> void* is subject to debate > (trap representation, ...). In practice, nobody cares because It just > works. (example of the nobody cares > https://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/glib/glib-Type-Conversion-Macros.html > ) > > > > In practice, I'm almost certain that the naïve code that just gives the > cgo.Handle to a C function as a void* is *much* safer that the pattern > suggested in the doc. > > > > So should the doc be changed, or am I missing some important piece ? > > It is not safe to convert a uintptr to an unsafe.Pointer when calling > a C function. The docs in the unsafe package are intended to be > precise, and in particular the compiler is aware of them. The > compiler applies special handling to a conversion from unsafe.Pointer > to uintptr in the argument to a function with no body like > syscall.Syscall. That special handling does not occur in calls to cgo > functions. While it will often work in practice, there are cases > where it will fail. > > One way to handle this kind of case is to write a tiny C wrapper in > the cgo comment that takes a uintptr and does the conversion to void* > in C. That conversion is safe, because the Go runtime will not be > aware of it and will never mistakenly treat the uintptr value as a > pointer value. > > 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+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/dc4eba12-cb08-4497-8d57-255a8213e608n%40googlegroups.com.