golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
122.7k stars 17.49k forks source link

x/tools/gopls: crash during internal/imports.scanDirForPackage (crash) #67156

Closed Sangwaniya closed 3 weeks ago

Sangwaniya commented 4 months ago

gopls version: v0.15.3/go1.21.6 gopls flags: update flags: proxy extension version: 0.41.4 environment: Visual Studio Code win32 initialization error: undefined issue timestamp: Thu, 02 May 2024 17:33:19 GMT restart history: Thu, 02 May 2024 17:30:10 GMT: activation (enabled: true)

ATTENTION: PLEASE PROVIDE THE DETAILS REQUESTED BELOW.

Describe what you observed.

panic: runtime error: slice bounds out of range [45:44]

goroutine 7611 [running]:
golang.org/x/tools/internal/imports.(*ModuleResolver).scanDirForPackage(0xc001898420, {{0xc004182665%3F, 0x81c8a92bb60e9ba5%3F}, 0x8%3F}, {0xc008108db0, 0x2c})
      mod.go:727  0x705
golang.org/x/tools/internal/imports.(*ModuleResolver).scan.func3({{0xc004182665%3F, 0xdc5e20%3F}, 0xc0067f8f90%3F}, {0xc008108db0%3F, 0x17d12a8%3F})
      mod.go:601  0x50
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0xc0067b7830, {0xc0071f8100, 0x37}, 0x0, {0x1200af8, 0xc0071f0380})
      walk.go:268  0x3d7
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0xc0067b7830, {0xc004182665, 0x2c}, 0x0, {0x1200b30, 0xc0067f8f70})
      walk.go:334  0x87b
golang.org/x/tools/internal/gopathwalk.walkDir({{0xc004182665%3F, 0xc0045a5f18%3F}, 0xc0045a5f18%3F}, 0xc0067f8f40, 0xc0067f8f30, {0x0%3F, 0x40%3F, 0x4%3F})
      walk.go:120  0x366
golang.org/x/tools/internal/gopathwalk.WalkSkip(...)
      walk.go:77
golang.org/x/tools/internal/imports.(*ModuleResolver).scan.func4()
      mod.go:626  0x2db
created by golang.org/x/tools/internal/imports.(*ModuleResolver).scan in goroutine 4670
      mod.go:610  0x465
gopls stats -anon { "DirStats": { "Files": 2035, "TestdataFiles": 0, "GoFiles": 1626, "ModFiles": 2, "Dirs": 528 }, "GOARCH": "amd64", "GOOS": "windows", "GOPACKAGESDRIVER": "", "GOPLSCACHE": "", "GoVersion": "go1.21.6", "GoplsVersion": "v0.15.3", "InitialWorkspaceLoadDuration": "7.6558984s", "MemStats": { "HeapAlloc": 31132976, "HeapInUse": 41328640, "TotalAlloc": 79278536 }, "WorkspaceStats": { "Files": { "Total": 2207, "Largest": 1654271, "Errs": 0 }, "Views": [ { "GoCommandVersion": "go1.21.6", "AllPackages": { "Packages": 417, "LargestPackage": 134, "CompiledGoFiles": 2217, "Modules": 49 }, "WorkspacePackages": { "Packages": 0, "LargestPackage": 0, "CompiledGoFiles": 0, "Modules": 0 }, "Diagnostics": 0 } ] } }
OPTIONAL: If you would like to share more information, you can attach your complete gopls logs. NOTE: THESE MAY CONTAIN SENSITIVE INFORMATION ABOUT YOUR CODEBASE. DO NOT SHARE LOGS IF YOU ARE WORKING IN A PRIVATE REPOSITORY.
hyangah commented 4 months ago

Thanks for the report @Sangwaniya Transferring to the gopls issue tracker.

adonovan commented 4 months ago

Looks like root.Path has the same length as dir, but is not a prefix of it.

func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) directoryPackageInfo {
    subdir := ""
    if dir != root.Path {
        subdir = dir[len(root.Path)+len("/"):] // slice bounds out of range [45:44]
    }
findleyr commented 3 months ago

Moving to the v0.17.0 milestone, since this seems to be affecting only one user (and in https://github.com/golang/vscode-go/issues/3401#issuecomment-2133246328, it appears that the cause may be related to a modified GOROOT).

Sangwaniya commented 3 months ago

hi @findleyr even after correcting the path and rebuilding gopls, still gopls is crashing Here are the logs: gopls version: v0.15.3/go1.21.6 gopls flags: update flags: proxy extension version: 0.41.4 environment: Visual Studio Code win32 initialization error: undefined issue timestamp: Fri, 31 May 2024 05:05:47 GMT restart history: Fri, 31 May 2024 05:00:53 GMT: activation (enabled: true)

ATTENTION: PLEASE PROVIDE THE DETAILS REQUESTED BELOW.

Describe what you observed.

panic: runtime error: slice bounds out of range [45:44]

goroutine 1561 [running]:
golang.org/x/tools/internal/imports.(*ModuleResolver).scanDirForPackage(0xc00099c210, {{0xc000580de5%3F, 0x336f25b8b5a7258c%3F}, 0x8%3F}, {0xc0007dd1d0, 0x2c})
      mod.go:727  0x705
golang.org/x/tools/internal/imports.(*ModuleResolver).scan.func3({{0xc000580de5%3F, 0x1215e20%3F}, 0xc000737ca0%3F}, {0xc0007dd1d0%3F, 0x1c212a8%3F})
      mod.go:601  0x50
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0xc000770cf0, {0xc000617a00, 0x37}, 0x0, {0x1650af8, 0xc0001bac40})
      walk.go:268  0x3d7
golang.org/x/tools/internal/gopathwalk.(*walker).walk(0xc000770cf0, {0xc000580de5, 0x2c}, 0x0, {0x1650b30, 0xc000737c60})
      walk.go:334  0x87b
golang.org/x/tools/internal/gopathwalk.walkDir({{0xc000580de5%3F, 0xc000bdff18%3F}, 0xc000bdff18%3F}, 0xc000737bf0, 0xc000737be0, {0x0%3F, 0x0%3F, 0x4%3F})
      walk.go:120  0x366
golang.org/x/tools/internal/gopathwalk.WalkSkip(...)
      walk.go:77
golang.org/x/tools/internal/imports.(*ModuleResolver).scan.func4()
      mod.go:626  0x2db
created by golang.org/x/tools/internal/imports.(*ModuleResolver).scan in goroutine 226
      mod.go:610  0x465
gopls stats -anon { "DirStats": { "Files": 2172, "TestdataFiles": 0, "GoFiles": 1626, "ModFiles": 2, "Dirs": 555 }, "GOARCH": "amd64", "GOOS": "windows", "GOPACKAGESDRIVER": "", "GOPLSCACHE": "", "GoVersion": "go1.21.6", "GoplsVersion": "v0.15.3", "InitialWorkspaceLoadDuration": "1.1454599s", "MemStats": { "HeapAlloc": 2580040, "HeapInUse": 5332992, "TotalAlloc": 36334560 }, "WorkspaceStats": { "Files": { "Total": 1, "Largest": 3429, "Errs": 0 }, "Views": [ { "GoCommandVersion": "go1.21.6", "AllPackages": { "Packages": 0, "LargestPackage": 0, "CompiledGoFiles": 0, "Modules": 0 }, "WorkspacePackages": { "Packages": 0, "LargestPackage": 0, "CompiledGoFiles": 0, "Modules": 0 }, "Diagnostics": 0 } ] } }
OPTIONAL: If you would like to share more information, you can attach your complete gopls logs. NOTE: THESE MAY CONTAIN SENSITIVE INFORMATION ABOUT YOUR CODEBASE. DO NOT SHARE LOGS IF YOU ARE WORKING IN A PRIVATE REPOSITORY.
hyangah commented 1 month ago

https://github.com/golang/vscode-go/issues/3456 is another crash report. The report came from Linux. (@feldgendler by any chance, are you using a modified go, or GOROOT source?)

feldgendler commented 1 month ago

My Go comes from an official tarball, GOROOT is not set.

feldgendler commented 1 month ago

I tried adding debug prints just before the crash.

Just before the crashing subdir = dir[len(root.Path)+len("/"):] line,

root.Path is /home/alexey/onboard/legio/bin/../tools/deps/../../_deps/go@1.22.5/pkg/mod dir is /home/alexey/onboard/legio/_deps/go@1.22.5/pkg/mod/mvdan.cc/gofumpt@v0.6.0

They just accidentally happen to have the same length.

findleyr commented 1 month ago

Thanks @feldgendler, that's useful information that the paths are completely unrelated. That suggests the bug is elsewhere (in the code that expects scanned directories to be a subdirectory of the root...).

My first guess is that there's something related to symlinks, but we'll need to investigate.

feldgendler commented 1 month ago

In /home/alexey/onboard/legio/bin, I have a few symlinks like this: dlv -> ../tools/deps/trampoline.sh. None of the symlinks point to a directory, but some of them point ot a file under ../tools/deps, which might explain the /home/alexey/onboard/legio/bin/../tools/deps prefix. However, that deps directory doesn't contain any symlinks, just plain files.

Now, I'd very much like to help debugging this because this bug is making my IDE almost completely useless. I don't understand the idea behind the code here — what should it really do with symlinks? Does it need to resolve them at all?

findleyr commented 1 month ago

Thanks, I will have more time to help investigate this later today.

In general, the philosophy around symlinks is:

  1. Don't rewrite paths: treat symlink paths like any other path, but...
  2. Keep track of symlinked directories to break cycles.

The code in question is very old, but has recently been modified to fix other bugs. It seems quite likely that some modification introduced a buggy handling of symlinks.

feldgendler commented 1 month ago

Thanks! Meanwhile, I tried replacing the crashing line with this:

    if s, ok := strings.CutPrefix(dir, root.Path+"/"); ok {
        subdir = s
    }

It seems to express the intent of the original line in a more robust way — assuming I understood it right.

This change seems to fix the issue for me — at least the scan now finishes without crashing.

findleyr commented 1 month ago

@feldgendler yes, at a minimum we'll do something like that. Now that we have a someone reproducing the issue, it would be great if we could track down the root cause.

If you don't mind, later today or tomorrow I'm going to come up with a list of things for you to check, which will help us narrow this down. In the meantime, please use your patch to unblock your work.

feldgendler commented 1 month ago

Sure! Thanks a lot.

findleyr commented 1 month ago

D'oh, I only just noticed that the scanned dir actually is a subdirectory of the root... if you clean the Root path.

Presumably you have a relative GOPATH, GOROOT, or replace directive, and that is being mishandled by goimports. I'm pretty confident that I can reproduce this -- peeking at the code indeed indicates that roots are not clean, and yet scanned directories are.

Thanks for taking the time to debug.

feldgendler commented 1 month ago

Is there anything else I can do to help you here?

findleyr commented 1 month ago

@feldgendler I've reproduced this crash in a test, and will send a fix shortly. If you could confirm that go env GOMODCACHE is unclean (includes /../), that would help me confirm that the context of my reproducer is accurate.

gopherbot commented 1 month ago

Change https://go.dev/cl/603635 mentions this issue: internal/imports: use clean GOMODCACHE for the scan root directory

Sangwaniya commented 1 month ago

@feldgendler yes correct

feldgendler commented 1 month ago
GOMODCACHE=/home/alexey/onboard/legio/bin/../tools/deps/../../_deps/go@1.22.5/pkg/mod
feldgendler commented 2 weeks ago

I just tested v0.16.2-pre.1, and the crash still happens.

findleyr commented 2 weeks ago

@feldgendler indeed we have not yet cherry-picked the fix to a prerelease (we were actually just testing our new release automation when we cut -pre.1). We will fix in a -pre.2, thanks.

feldgendler commented 2 weeks ago

I'm not good at this syntax — is there a Go version expression I could use with go install to test the fix?

findleyr commented 2 weeks ago

@feldgendler the best way to test the fix would be to install gopls@master, which you can do with the following command (we need to install from source as there is a replace directive in the gopls go.mod file during development).

git clone go.googlesource.com/tools
cd tools/gopls
go install
feldgendler commented 2 weeks ago

No crash when installed in this way, thank you!

dottedmag commented 2 weeks ago

(we need to install from source as there is a replace directive in the gopls go.mod file during development)

Is this a leftover from before workspaces were added, or is there a reason to keep this replacement instead of go.work?

findleyr commented 2 weeks ago

@dottedmag this is from before workspaces were added, but no we keep it because best practice is to not check in go.work files (see documentation here: https://go.dev/ref/mod#go-work-file).

In particular, while correctness requires that golang.org/x/tools/gopls imports the local golang.org/x/tools during development (because it uses the internals of x/tools), we want to support developers working on additional modules if they so choose. Checking in a go.work would circumvent that choice.

gopherbot commented 1 week ago

Change https://go.dev/cl/609215 mentions this issue: [gopls-release-branch.0.16] internal/imports: use a clean GOMODCACHE for the scan root directory