-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
What did you do?
I am editing code in a GOPATH project. $GOPATH/src/p is the root of a large Go source tree (all of our internal code at my company).
I can't make the crash happen with a small GOPATH; I suspect it requires a large amount of code to enlarge a race window or something like that. But I did minimize the repro a little:
$GOPATH/src/p/
├─ a/
├─ scratch/x.go
└─ ... many other deeply nested directories including many Go packages
The directory a is empty.
The file scratch/x.go contains a little bit of code (doesn't much matter what):
package scratch
func f() {
x := "hello"
}
I am using gopls via govim. My working directory is $GOPATH/src/p/a and I edit x.go:
vim ../scratch/x.go
and immediately start making edits to the file (say, moving my cursor to the end of one of the lines and holding down backspace).
What did you expect to see?
No crashes
What did you see instead?
Govim freezes because gopls has crashed. Here is a stack trace:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x50 pc=0x7e4dba]
goroutine 6362 [running]:
golang.org/x/tools/internal/lsp/source.IsGenerated(0xef2aa0, 0xc010c9d4a0, 0x0, 0x0, 0xc00f6fd950, 0x2e, 0x0)
/home/caleb/p/go/src/golang.org/x/tools/internal/lsp/source/util.go:90 +0x3a
golang.org/x/tools/internal/lsp.(*Server).didModifyFiles(0xc000296580, 0xef2aa0, 0xc010c9d4a0, 0xc00fcd7c20, 0x1, 0x1, 0x1, 0x0, 0x0)
/home/caleb/p/go/src/golang.org/x/tools/internal/lsp/text_synchronization.go:244 +0xecf
golang.org/x/tools/internal/lsp.(*Server).didChange(0xc000296580, 0xef2aa0, 0xc010c9d4a0, 0xc00fcf21e0, 0x0, 0x0)
/home/caleb/p/go/src/golang.org/x/tools/internal/lsp/text_synchronization.go:117 +0x266
golang.org/x/tools/internal/lsp.(*Server).DidChange(0xc000296580, 0xef2aa0, 0xc010c9d4a0, 0xc00fcf21e0, 0xc00fcf21e0, 0x0)
/home/caleb/p/go/src/golang.org/x/tools/internal/lsp/server_gen.go:36 +0x49
golang.org/x/tools/internal/lsp/protocol.serverDispatch(0xef2aa0, 0xc010c9d4a0, 0xf065e0, 0xc000296580, 0xc00fcf21b0, 0x7f06743d80c0, 0xc010c9d440, 0x0, 0xedff00, 0xc002215550)
/home/caleb/p/go/src/golang.org/x/tools/internal/lsp/protocol/tsserver.go:120 +0x1a7e
golang.org/x/tools/internal/lsp/protocol.ServerHandler.func1(0xef2aa0, 0xc010c9d4a0, 0xc00fcf21b0, 0x7f06743d80c0, 0xc010c9d440, 0x311e159c, 0x134bde0)
/home/caleb/p/go/src/golang.org/x/tools/internal/lsp/protocol/protocol.go:63 +0xc5
golang.org/x/tools/internal/lsp/lsprpc.handshaker.func1(0xef2aa0, 0xc010c9d4a0, 0xc00fcf21b0, 0x7f06743d80c0, 0xc010c9d440, 0x0, 0x0)
/home/caleb/p/go/src/golang.org/x/tools/internal/lsp/lsprpc/lsprpc.go:557 +0x452
golang.org/x/tools/internal/jsonrpc2.MustReplyHandler.func1(0xef2aa0, 0xc010c9d4a0, 0xc0102e3c20, 0x7f06743d80c0, 0xc010c9d440, 0xc00fd508a0, 0x1)
/home/caleb/p/go/src/golang.org/x/tools/internal/jsonrpc2/handler.go:35 +0xcf
golang.org/x/tools/internal/jsonrpc2.AsyncHandler.func1.2(0xc0000425a0, 0xc010c9dc20, 0xc0007ca200, 0xef2aa0, 0xc010c9d4a0, 0xc0102e3c20, 0x7f06743d80c0, 0xc010c9d440)
/home/caleb/p/go/src/golang.org/x/tools/internal/jsonrpc2/handler.go:103 +0x86
created by golang.org/x/tools/internal/jsonrpc2.AsyncHandler.func1
/home/caleb/p/go/src/golang.org/x/tools/internal/jsonrpc2/handler.go:100 +0x173
If I edit the file from the project root ($GOPATH/src/p) or from inside scratch, the crash doesn't seem to happen. Being inside another directory and editing the file as ../scratch/x.go seems to matter.
I poked around in the code a little and I see that the map in question is indeed populated with nil snapshots a few lines earlier here so that when we get down to here we call source.IsGenerated with snapshot == nil.
I tried making the trivial change of not filling snapshotByURI with nils but that broke something else. I stared at the code for a while but it's hard for me to tell what the intent was.
It also seems like there's an unreachable condition immediately before the crash line here.
I'm guessing that for someone familiar with the code, the bug and fix will be obvious.
Build info
(I updated to latest to confirm the bug but I saw this with a variety of older gopls versions as well.)
golang.org/x/tools/gopls master
golang.org/x/tools/gopls@(devel)
github.com/BurntSushi/[email protected] h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/google/[email protected] h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
github.com/sergi/[email protected] h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
golang.org/x/[email protected] h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/[email protected] h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
golang.org/x/[email protected] => ../
golang.org/x/[email protected] h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
honnef.co/go/[email protected] h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k=
mvdan.cc/[email protected] h1:t8TAw9WgTLghti7RYkpPmqk4JtQ3+wcP5GgZqgWeWLQ=
mvdan.cc/xurls/[email protected] h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=
cc:
- @stamblerre -- I think you added this nil snapshot code back in CL 215908.
- @heschik -- Looks like you reviewed and touched most of this code.
- @myitcv -- I found this via govim and this is similar to your "Stack trace 2" in x/tools/cmd/gopls: nil pointer dereference when creating new file #34366.