CGO 已知指针检查中的实现错误

CGO known implementation bug in pointer checks

根据 CGO (https://pkg.go.dev/cmd/cgo) 的文档,实现中存在一个已知错误:

Note: the current implementation has a bug. While Go code is permitted to write nil or a C pointer (but not a Go pointer) to C memory, the current implementation may sometimes cause a runtime error if the contents of the C memory appear to be a Go pointer. Therefore, avoid passing uninitialized C memory to Go code if the Go code is going to store pointer values in it. Zero out the memory in C before passing it to Go.

我在 GitHub 的问题跟踪器中寻找过这个,但在那里找不到。有人可以详细说明为什么会发生这种情况吗?运行时如何在未初始化的 C 内存中找到 Go 指针?

例如。假设我将一个未初始化的 char 数组传递给 C 中的 Go 函数,运行时如何解释此内存中的 Go 指针?

此外,“如果 Go 代码要在其中存储指针值”部分让我感到困惑。为什么稍后使用此内存很重要?

I looked for this in the issue tracker at GitHub but can't find it there.

这条评论提到的错误是https://golang.org/issue/19928,这当然不容易找到。

Could someone please elaborate on why this might happen? How does the runtime find Go pointers in uninitialized C memory?

在垃圾收集周期的某些部分,收集器打开“write barrier”用于写入 Go 堆中的指针,记录先前存储的指针值以确保在期间不会丢失它GC 扫描。

这里的 bug 是写屏障有时也会记录先前存储的指针值 在 Go 堆之外。如果该值看起来像一个 Go 指针,垃圾收集器可能会尝试递归扫描它,如果它实际上不是一个有效指针,则可能会崩溃。

Eg. let's say I am passing an uninitialized char array to a Go function from C, how can the runtime interpret a Go pointer in this memory?

如果传递给 Go 的未初始化数据属于不包含任何指针的类型,则不应出现此错误。因此,特别是对于 char 数组,无论哪种方式都应该没问题。

Also, the "if the Go code is going to store pointer values in it" part confuses me. Why does later use of this memory matter?

编译器在指针类型的存储指令处插入写屏障。如果 Go 程序不存储指针,那么编译器就不会发出任何写屏障,也不会触发写屏障中的 bug。