What are the cgo pointer-passing rules, and how does runtime.Pinner help?
Question 427HardGo 1.22 to 1.25
The GC may move goroutine stacks and must be able to see every Go pointer. The rules, enforced at runtime when GODEBUG=cgocheck=1 (the default):
- Go may pass a Go pointer to C only if the memory it points to contains no Go pointers. Passing a
[]bytebuffer is fine. Passing a struct with a*Tfield or a string field is not. - C must not keep a Go pointer after the call returns (no storing it in a global, no using it from another thread later).
- Go code may not store a Go pointer in C memory, and a Go function called from C (via
//export) may not return a Go pointer (so no strings, slices, maps or channels). Pinned pointers are the exception.
// OK: pointer to Go memory that has no Go pointers inside, used only during call
buf := make([]byte, 4096)
n := C.fill((*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))
// Need C to hold onto Go objects? Use runtime/cgo.Handle (an opaque integer):
h := cgo.NewHandle(myGoValue) // import "runtime/cgo"
C.register_callback(C.uintptr_t(h))
// later in the exported callback: v := cgo.Handle(id).Value(); h.Delete()
runtime.Pinner (Go 1.21) pins a Go object so that C may keep the pointer, and lets Go memory that is passed to C contain pointers to pinned objects. You must call Unpin() afterwards.
Setting GOEXPERIMENT=cgocheck2 enables expensive write-barrier checks for debugging. When C needs its own long-lived data, allocate it with C.malloc and free it yourself.
More on Modules, Packages & Tooling
- Q425How does go generate work, and what are best practices around it?
- Q426What are the tradeoffs of using cgo? When would you avoid it?
- Q428How do you cross-compile Go and produce a fully static binary for a scratch container?
- Q429How do you inject a version string at build time with -ldflags? What does this program print?
- Q430What build metadata does a Go binary carry, and how do you make builds reproducible?
- Q431What does go vet catch? What does it report for the code below?