#!stacks
"sigpanic" && "growslice:+17"
Issue created by stacks.
Another impossible crash: the compiler generates code to load the *Snapshot
type descriptor from rodata in R4, then calls growslice, which experiences a SEGV while loading from this register at L194.
golang.org/x/tools/gopls/internal/cache.(*Session).ExpandModificationsToDirectories STEXT size=1504 args=0x30 locals=0x318 funcid=0x0 align=0x0
...
0x019c 00412 L0967 MOVD $type:*golang.org/x/tools/gopls/internal/cache.Snapshot(SB), R4
0x01a4 00420 L0967 CALL runtime.growslice(SB)
...
runtime.growslice STEXT size=1536 args=0x28 locals=0x58 funcid=0x0 align=0x0
0x0000 00000 L0177 MOVD 16(g), R16
0x0004 00004 L0177 CMP R16, RSP
0x0008 00008 L0177 BLS 1500
0x000c 00012 L0177 MOVD.W R30, -96(RSP)
0x0010 00016 L0177 MOVD R29, -8(RSP)
0x0014 00020 L0177 SUB $8, RSP, R29
0x0018 00024 L0178 SUB R3, R1, R3
0x001c 00028 L0190 TBNZ $63, R1, 1476
0x0020 00032 L0194 MOVD (R4), R5 <----- SEGV
Unlike all previous crashes, which have been loads from SP or g, this one is an ordinary register. I'm struggling to think of a realistic scenario in which an application bug (e.g. data race, misuse of unsafe) could cause this problem. It's one thing for buggy code to clobber arbitrary memory, but this crash means that a register has been corrupted. R4 has somehow been clobbered between the load from rodata (which can't have been written) and the load at L194, with no intervening function calls. I suppose it's possible that the runtime suspended the g in between, and the memory where the g's register file was saved was corrupted, but that seems very unlikely, not least because there is nothing that would synchronously invoke the scheduler in this handful of instructions.
I'm starting to suspect that this is a bug not in the application, but in the runtime or hardware. @prattmic
This stack fcv6BQ
was reported by telemetry:
crash/crash
runtime.throw:+9,+0x37
runtime.sigpanic:+33,+0x223
runtime.growslice:+17,+0x20
golang.org/x/tools/gopls/internal/cache.(*Session).ExpandModificationsToDirectories:+9,+0x17f
golang.org/x/tools/gopls/internal/server.(*server).didModifyFiles:+34,+0x2eb
golang.org/x/tools/gopls/internal/server.(*server).DidChangeWatchedFiles:+13,+0x1fb
golang.org/x/tools/gopls/internal/protocol.serverDispatch:+634,+0x5437
golang.org/x/tools/gopls/internal/lsprpc.(*StreamServer).ServeStream.ServerHandler.func4:+5,+0x73
golang.org/x/tools/gopls/internal/lsprpc.(*StreamServer).ServeStream.handshaker.func5:+52,+0x68f
golang.org/x/tools/gopls/internal/protocol.Handlers.MustReplyHandler.func1:+2,+0xbf
golang.org/x/tools/gopls/internal/protocol.Handlers.AsyncHandler.func2.2:+3,+0x8f
runtime.goexit:+0,+0x3
golang.org/x/tools/gopls@v0.20.0 go1.24.4 darwin/arm64 other,vscode (1)
Comment From: gabyhelp
Related Issues
- x/tools/gopls: growslice crashes while zeroing #74932
- x/tools/gopls: sigpanic in methods of persistent.Map (corrupt g) #74870
- x/tools/gopls: automated issue report (crash) #40449 (closed)
- x/tools/gopls: SEGV in HasSuffix (corrupt string) #74348
- x/tools/gopls: automated issue report (crash) #40819 (closed)
- x/tools/gopls: impossible SEGV in regexp/syntax.MatchRunePos #73090
- x/tools/gopls: call to IsGenerated ocassionally has nil Snapshot causing panic #41778 (closed)
- x/tools/gopls: nil deref in 'go vendor' Snapshot.GoCommandInvocation #73891
- gopls: panic #42077 (closed)
- x/tools/gopls: panic because of nil pointer in cache.fileWasSaved #37687 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: prattmic
there is nothing that would synchronously invoke the scheduler in this handful of instructions
The beginning of this function does have a stack check:
runtime.growslice STEXT size=1536 args=0x28 locals=0x58 funcid=0x0 align=0x0
0x0000 00000 L0177 MOVD 16(g), R16
0x0004 00004 L0177 CMP R16, RSP
0x0008 00008 L0177 BLS 1500
The BLS 1500
is presumably a jump down to a call to runtime.morestack
. This would be used to grow the stack, or do synchronous preemption (morestack
handles both). Upon return, morestack
would continue execution of the function.
So if preemption corrupted R4, it didn't need to be asynchronous preemption. Still, corruption of an ordinary general purpose register would be a fairly surprising bug.
cc @golang/runtime