1

For a non-struct slice in Go

a := []byte{0,1,2,3,4,5,6,7}

And pass to C via unsafe.Pointer()

C.some_method((*C.char)(unsafe.Pointer(&a[0])), C.int(len(a)))

Is it safe to write anything into this pointer with caution on it's length?

void some_method(char* a, int a_len) {
    for (int i=0; i<a_len; i++) {
        a[i] = i+1;
    }
}
Wilson Luniz
  • 459
  • 2
  • 7
  • 18
  • https://pkg.go.dev/cmd/cgo#hdr-Passing_pointers, yes you can write to values within the rules laid out in the docs. – JimB Jun 03 '23 at 12:08
  • @JimB I can only found things like you can "pass" pointer bewteen Go and C with certain criteria but seems nothing explicitly saying it's ok to write in peers' heap. Should I simply consider anything allowed to pass between are also writable? (if not accounting thread safe) – Wilson Luniz Jun 03 '23 at 18:42
  • There are some corner cases where https://pkg.go.dev/runtime#KeepAlive might help prevent items from being recycled before you are ready for that to happen. I would have thought that would be mentioned in the cgo doc but it isn't. – Tinkerer Jun 03 '23 at 18:43
  • @Tinkerer Oh! Yes. You reminded me I also need to consider GC might move the pointer address! Need to consider this too! – Wilson Luniz Jun 04 '23 at 18:09
  • @WilsonLuniz that's *exactly* what the pointer-passing rules are about. You can safely use the pointer without worrying about the GC moving it for the duration of the C function call, but it's illegal to *retain* it past the function's return (if you need something like that, retain a `cgo.Handle` instead). – hobbs Jun 07 '23 at 05:15

1 Answers1

0

After a little research and reading comments, I think here're a few things to caution:

  • For async/multi-thread in C, you need to make sure GC won't collect you pointer. This can be done via runtime.KeepAlive()
  • GC may move you memory allocation. unsafe.Pointer won't get update if it do so(https://pkg.go.dev/unsafe#Pointer). But there's a pin mechanism coming soon(https://github.com/golang/go/issues/46787).
  • //go:uintptrescapes unlikely to work for CGO, use with caution.
Wilson Luniz
  • 459
  • 2
  • 7
  • 18
  • That bug also mentioned `//go:uintptrescapes` which likely deserves a mention of its own here. – Tinkerer Jun 05 '23 at 19:46
  • Worth to mention but it I reckon if it's a bug. Is there any issue/discussion I can read from? – Wilson Luniz Jun 07 '23 at 05:03
  • This is frequently used when doing syscalls from go where the raw syscall API is expecting a ptr as one of the arguments. Converting a memory address to a `uintptr` breaks the ptr keep alive. By prefixing the go function with this pragma comment the compiler delays GC on converted ptrs until after the call completes. This is a more implicit `runtime.KeepAlive` trick. – Tinkerer Jun 07 '23 at 05:35