In #12416, we (mostly @ianlancetaylor, I think) defined some restrictions on what C functions can do with Go pointers.
The current restrictions say, “The C code … must not store any Go pointers in Go memory, even temporarily.”
They do not prohibit the C code from storing non-Go pointers in Go memory, but I've been thinking about the pointer check a lot lately, and #20427 (comment) reminded me that C compilers can generate some pretty gnarly code.
In particular, C11 has a proper threading model, and a C11 compiler is allowed to assume that non-atomic writes do not race. It can rewrite them as, say, a store followed by an add, or a store of a spilled temporary followed by a load of that temporary and a store of the actual pointer. (Fortunately, I do not yet have an example of a C compiler actually generating such code.)
So now I'm not sure that the cgo pointer check is really strong enough after all: writes of non-Go pointers to Go pointer slots from C can, at least theoretically, race with the garbage collector tracing those slots, and cause it to observe invalid pointers.
To address that problem, I think we need to do one of:
Strengthen the existing sentence: “The C code … must not store any pointers in Go memory, even temporarily,” or
Add another clause: “The C code may store non-Go pointers in Go memory, but must ensure that each such store occurs atomically.”
I think the rules are strong enough. I think that what you are discussing is the fact that optimizing C compilers may generate code that causes the rules to be broken even though the C code looks OK to the programmer.
I'm OK with adding a sentence warning about C compiler optimizations if you want to add one.