Skip to content

Commit 979d74e

Browse files
committed
internal/lsp: fix race condition in metadata handling
The metadata was being added to the cache before it was fully computed. Change-Id: I6931476a715f0383f7739fa4e950dcaa6cbec4fe Reviewed-on: https://go-review.googlesource.com/c/tools/+/204562 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
1 parent 423eeae commit 979d74e

File tree

3 files changed

+19
-13
lines changed

3 files changed

+19
-13
lines changed

internal/lsp/cache/load.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ func (s *snapshot) load(ctx context.Context, uri span.URI) ([]*metadata, error)
4545
if err == context.Canceled {
4646
return nil, errors.Errorf("no metadata for %s: %v", uri.Filename(), err)
4747
}
48-
4948
log.Print(ctx, "go/packages.Load", tag.Of("packages", len(pkgs)))
5049
if len(pkgs) == 0 {
5150
if err == nil {
@@ -149,7 +148,7 @@ func (s *snapshot) updateMetadata(ctx context.Context, uri span.URI, pkgs []*pac
149148
log.Print(ctx, "go/packages.Load", tag.Of("package", pkg.PkgPath), tag.Of("files", pkg.CompiledGoFiles))
150149

151150
// Set the metadata for this package.
152-
if err := s.updateImports(ctx, packagePath(pkg.PkgPath), pkg, cfg); err != nil {
151+
if err := s.updateImports(ctx, packagePath(pkg.PkgPath), pkg, cfg, map[packageID]struct{}{}); err != nil {
153152
return nil, nil, err
154153
}
155154
m := s.getMetadata(packageID(pkg.ID))
@@ -167,33 +166,36 @@ func (s *snapshot) updateMetadata(ctx context.Context, uri span.URI, pkgs []*pac
167166
return results, prevMissingImports, nil
168167
}
169168

170-
func (s *snapshot) updateImports(ctx context.Context, pkgPath packagePath, pkg *packages.Package, cfg *packages.Config) error {
169+
func (s *snapshot) updateImports(ctx context.Context, pkgPath packagePath, pkg *packages.Package, cfg *packages.Config, seen map[packageID]struct{}) error {
170+
id := packageID(pkg.ID)
171+
if _, ok := seen[id]; ok {
172+
return errors.Errorf("import cycle detected: %q", id)
173+
}
171174
// Recreate the metadata rather than reusing it to avoid locking.
172175
m := &metadata{
173-
id: packageID(pkg.ID),
176+
id: id,
174177
pkgPath: pkgPath,
175178
name: pkg.Name,
176179
typesSizes: pkg.TypesSizes,
177180
errors: pkg.Errors,
178181
config: cfg,
179182
}
183+
seen[id] = struct{}{}
180184
for _, filename := range pkg.CompiledGoFiles {
181185
uri := span.FileURI(filename)
182186
m.files = append(m.files, uri)
183187

184188
s.addID(uri, m.id)
185189
}
186190

187-
// Add the metadata to the cache.
188-
s.setMetadata(m)
189-
191+
copied := make(map[packageID]struct{})
192+
for k, v := range seen {
193+
copied[k] = v
194+
}
190195
for importPath, importPkg := range pkg.Imports {
191196
importPkgPath := packagePath(importPath)
192197
importID := packageID(importPkg.ID)
193198

194-
if importPkgPath == pkgPath {
195-
return errors.Errorf("cycle detected in %s", importPath)
196-
}
197199
m.deps = append(m.deps, importID)
198200

199201
// Don't remember any imports with significant errors.
@@ -206,10 +208,14 @@ func (s *snapshot) updateImports(ctx context.Context, pkgPath packagePath, pkg *
206208
}
207209
dep := s.getMetadata(importID)
208210
if dep == nil {
209-
if err := s.updateImports(ctx, importPkgPath, importPkg, cfg); err != nil {
211+
if err := s.updateImports(ctx, importPkgPath, importPkg, cfg, copied); err != nil {
210212
log.Error(ctx, "error in dependency", err)
211213
}
212214
}
213215
}
216+
217+
// Add the metadata to the cache.
218+
s.setMetadata(m)
219+
214220
return nil
215221
}

internal/lsp/cmd/test/check.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnosti
6161
}
6262
_, found := got[expect]
6363
if !found {
64-
t.Errorf("missing diagnostic %q", expect)
64+
t.Errorf("missing diagnostic %q, %v", expect, got)
6565
} else {
6666
delete(got, expect)
6767
}

internal/lsp/testdata/nodisk/nodisk.overlay.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ import (
66

77
func _() {
88
foo.Foo() //@complete("F", Foo, IntFoo, StructFoo)
9-
}
9+
}

0 commit comments

Comments
 (0)