Skip to content

Fix concurrent extractionCache read/write#4562

Merged
johnfav03 merged 1 commit into
microsoft:mainfrom
johnfav03:fix-autoimport-map-race
Jul 9, 2026
Merged

Fix concurrent extractionCache read/write#4562
johnfav03 merged 1 commit into
microsoft:mainfrom
johnfav03:fix-autoimport-map-race

Conversation

@johnfav03

@johnfav03 johnfav03 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Fixes an issue uncovered in #4380 (comment), #4380 (comment), and #4380 (comment) (cypress); building the auto-import index in registryBuilder.updateIndexes spawns workers that populate the shared extractionCache map. However, reading this map in the @types fallback loop is unprotected by the lock and can cause a read/write data race.

Copilot AI review requested due to automatic review settings July 8, 2026 16:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a concurrency bug in the auto-import registry builder where the @types fallback loop could read from extractionCache while worker goroutines were concurrently writing to it, causing a Go concurrent map read/write race during registryBuilder.updateIndexes.

Changes:

  • Guard extractionCache reads in the @types fallback loop with extractionMu to prevent concurrent map access.
  • Add a regression test that exercises the fallback path across many packages to ensure the indexing flow does not crash under concurrent extraction.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
internal/ls/autoimport/registry.go Locks extractionCache reads during @types fallback candidate evaluation to eliminate concurrent map read/write.
internal/ls/autoimport/registry_test.go Adds a test that builds an auto-import index with many packages that require @types fallback, covering the previously racy path.

@@ -963,7 +974,10 @@ func (b *registryBuilder) updateIndexes(ctx context.Context, change RegistryChan

// For packages whose main extraction yielded nothing, fall back to @types.
for _, pkg := range typesFallbackCandidates {
if extractionCache[pkg.realpath] != nil || seen[pkg.typesRealpath] {
extractionMu.Lock()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wg.Wait has happened, so there should be no goroutines still writing to this, so I don't think this is right? I think the full race output would be helpful

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yikes, the race is below

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly - because it keeps iterating and spawns a new goroutine on each subsequent iteration, and that workers write can race with the parent goroutine still running the loop.

@jakebailey jakebailey requested a review from andrewbranch July 8, 2026 17:34
@johnfav03 johnfav03 added this pull request to the merge queue Jul 9, 2026
Merged via the queue into microsoft:main with commit 487baf0 Jul 9, 2026
21 checks passed
@johnfav03 johnfav03 deleted the fix-autoimport-map-race branch July 9, 2026 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants