Maybe a Bug? The Go compiler stores a stack pointer into a global object

223 views
Skip to first unread message

Jinbao Chen

unread,
Aug 2, 2023, 1:03:31 PM8/2/23
to golang-nuts
I use go1.20.5 to compile the following code. 
package main

func use(...interface{}) {
 
}

func main() {
    testCases := [...][][]int{
        {{42}},
        {{1, 2}},
        {{3, 4, 5}},
        {{}},
        {{1, 2}, {3, 4, 5}, {}, {7}},
    }
    for _, testCase := range testCases {
        use(testCase)
    }
}
In the generated SSA and assembly code, I notice that the Go compiler generates some instructions that store a stack pointer(point to the stack-allocated array) into a global slice header.

Just like the assembly code below, the MOV instruction at 0x4585bf stores a stack pointer into a global object: 
  0x458589 48c744240800000000       MOVQ $0x0, 0x8(SP)
  0x458592 48c74424082a000000 MOVQ $0x2a, 0x8(SP)
testCases := [...][][]int{
  0x45859b 48c705c28e060001000000 MOVQ $0x1, 0x68ec2(IP)
  0x4585a6 48c705bf8e060001000000 MOVQ $0x1, 0x68ebf(IP)
  0x4585b1 833d988d090000 CMPL $0x0, runtime.writeBarrier(SB)
  0x4585b8 750e JNE 0x4585c8
  0x4585ba 488d442408 LEAQ 0x8(SP), AX
  0x4585bf 4889059a8e0600 MOVQ AX, 0x68e9a(IP)
  0x4585c6 eb11 JMP 0x4585d9
  0x4585c8 488d3d918e0600 LEAQ 0x68e91(IP), DI
  0x4585cf 488d442408 LEAQ 0x8(SP), AX
  0x4585d4 e8e7cfffff CALL runtime.gcWriteBarrier(SB)

I have read the comments in slicelit,  but I didn't find any operations that can generate such stores. As far as I know, pointers to stack objects cannot be stored in global objects. So is this a compiler bug? Or the Go compiler does this on purpose to achieve some optimization I don't know yet?

Thanks

Keith Randall

unread,
Aug 2, 2023, 11:39:00 PM8/2/23
to golang-nuts
Yes, that looks very, very wrong. It looks like this issue goes back to at least 1.16.
If you can open an issue at https://github.com/golang/go/issues we can investigate.

Qingwei Li

unread,
Aug 3, 2023, 1:41:35 AM8/3/23
to golang-nuts
I notice that Go1.17.7 still allocates the array on heap by calling newobject while Go1.18 allocates the array on stack. I also notice that in the release note of Go1.18 that "The garbage collector now includes non-heap sources of garbage collector work". Does the GC in 1.18 and following versions of Go ignore some global memory area when marking?

Michael Knyszek

unread,
Aug 3, 2023, 5:49:25 AM8/3/23
to golang-nuts
That line (the full sentence is "The garbage collector now includes non-heap sources of garbage collector work (e.g., stack scanning) when determining how frequently to run.") is unrelated. It only refers to a change in accounting for what gets included in the GOGC calculation, not a change in what was marked and scanned by the GC.

Jinbao Chen

unread,
Aug 3, 2023, 9:11:20 PM8/3/23
to golang-nuts
Thanks for the relpy. I have opened an issue on github: https://github.com/golang/go/issues/61730
Reply all
Reply to author
Forward
0 new messages