5

According to the documentation of CGO (https://pkg.go.dev/cmd/cgo), there is a known bug in the implementation:

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.

I looked for this in the issue tracker at GitHub but can't find it there. Could someone please elaborate on why this might happen? How does the runtime find Go pointers in uninitialized C memory?

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?

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?

tecs-x
  • 308
  • 3
  • 12
antnio96
  • 53
  • 3
  • _"... how can the runtime interpret a Go pointer in this memory"_, it won't unless you use it to store pointers. It answer that in the next sentence you quoted: _"avoid passing uninitialized C memory to Go code if the Go code is going to store pointer values in it"_. – JimB Jul 13 '21 at 13:38
  • @JimB, I'm not a native speaker, but to me it appears that the quoted part of the manual does not say about _chasing_ pointers in a C memory block, it rather says about storing pointers _into_ it—that is, directly. So, I, for one, support the OP's confusion. What do you think? – kostix Jul 13 '21 at 14:39
  • @kostix: I think it all boils down to _"avoid passing uninitialized C memory to Go code if the Go code is going to store pointer values in it"_, which is a clear and simple instruction to follow. The rest is trying to give a little background without having to completely explain how the garbage collector scans for pointers. – JimB Jul 13 '21 at 14:54
  • What confuses me is that this is referred to as a bug. Isn't this more of a fail-safe which has a side-effect of springing upon the unsuspecting programmer? – Zyl Jul 13 '21 at 18:46
  • The quote gives a simple instruction about how to avoid the problem but the instruction seems disconnected from the first sentences of the quote. The beginning seems to describe a broader problem. I would like a more detailed description of the bug and the conditions that trigger it. This would not require a complete explaination of the scan for pointers. It is strange to me that a new condition, reducing the scope of the bug, first appears after "Therefore,". – antnio96 Jul 14 '21 at 12:39

1 Answers1

3

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

The bug to which this comment refers is https://golang.org/issue/19928, which is admittedly not easy to find.

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

During certain parts of a garbage collection cycle, the collector turns on a “write barrier” for writes to pointers in the Go heap, recording the previously-stored pointer value to ensure that it is not missed during the GC scan.

The bug here is that the write barrier sometimes also records the previously-stored pointer value for pointers outside the Go heap. If that value looks like a Go pointer, the garbage collector may try to scan it recursively, and could crash if it isn't actually a valid pointer.

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?

This bug should not occur if the uninitialized data passed to Go is of a type that does not contain any pointers. So for a char array in particular you should be fine either way.

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?

The compiler inserts write barriers at store instructions for pointer types. If the Go program does not store pointers, then the compiler will not emit any write barriers, and the bug in the write barrier will not be triggered.

bcmills
  • 4,391
  • 24
  • 34