Skip to content

[Bug] Data race in autoCompleteSuggestions.sort() during concurrent access #4716

@e-gineer

Description

@e-gineer

Bug Description

The sort() method in pkg/interactive/autocomplete_suggestions.go has a data race when called concurrently from multiple goroutines. This can lead to data corruption or crashes during autocomplete initialization.

Location

File: pkg/interactive/autocomplete_suggestions.go
Lines: 23-39
Function: autoCompleteSuggestions.sort()

Issue

The sort() method modifies slices in place without any synchronization mechanism. When multiple goroutines call sort() (or initialiseSuggestions() which calls sort()), they race to read and write the same memory locations.

func (s *autoCompleteSuggestions) sort() {
    sortSuggestions := func(suggestions []prompt.Suggest) {
        sort.Slice(suggestions, func(i, j int) bool {
            return suggestions[i].Text < suggestions[j].Text
            // ^^^ DATA RACE: Concurrent reads/writes to suggestions slice
        })
    }

    sortSuggestions(s.schemas)
    sortSuggestions(s.unqualifiedTables)
    // ... more sorts
}

Impact

  • Severity: Medium
  • Symptoms: Data corruption, crashes, inconsistent autocomplete suggestions
  • Conditions: Occurs when autocomplete is initialized from multiple goroutines simultaneously
  • Race Detector Output:
    WARNING: DATA RACE
    Read at 0x00c000820d20 by goroutine 27
    Previous write at 0x00c000820d20 by goroutine 29
    

Steps to Reproduce

  1. Run the test with race detector:
    go test -race ./pkg/interactive/ -run TestAutocompleteSuggestions_ConcurrentSort
  2. Race detector reports data race
  3. Or, call sort() from multiple goroutines:
    suggestions := newAutocompleteSuggestions()
    go suggestions.sort()
    go suggestions.sort()
    go suggestions.sort()

Detection

Found via concurrent access testing with Go's race detector:

  • Test: TestAutocompleteSuggestions_ConcurrentSort
  • File: pkg/interactive/interactive_client_autocomplete_extended_test.go
  • Run with: go test -race

Suggested Fixes

Option 1: Add Mutex Protection

type autoCompleteSuggestions struct {
    mu                  sync.RWMutex
    schemas             []prompt.Suggest
    unqualifiedTables   []prompt.Suggest
    // ... other fields
}

func (s *autoCompleteSuggestions) sort() {
    s.mu.Lock()
    defer s.mu.Unlock()
    
    // ... existing sort logic
}

Option 2: Document as Not Thread-Safe

If concurrent access is not expected in practice:

// sort sorts all suggestion lists alphabetically.
// NOTE: This method is NOT thread-safe. Callers must ensure
// exclusive access to the autoCompleteSuggestions instance.
func (s *autoCompleteSuggestions) sort() {
    // ... existing logic
}

Option 3: Make sort() Return New Slices

Instead of sorting in-place, return sorted copies:

func (s *autoCompleteSuggestions) sort() {
    s.schemas = sortSuggestions(s.schemas)
    s.unqualifiedTables = sortSuggestions(s.unqualifiedTables)
    // ...
}

func sortSuggestions(suggestions []prompt.Suggest) []prompt.Suggest {
    sorted := make([]prompt.Suggest, len(suggestions))
    copy(sorted, suggestions)
    sort.Slice(sorted, func(i, j int) bool {
        return sorted[i].Text < sorted[j].Text
    })
    return sorted
}

Recommendation

Option 1 (Mutex Protection) is recommended if concurrent access is possible. Option 2 (Documentation) is acceptable if the current architecture guarantees single-threaded access.

Related

  • Found during Wave 2 Core Functionality testing (Task 7: Autocomplete Tests)
  • Part of bug hunting focus per Wave 2 Quality Override guidelines
  • Detected using Go's race detector (-race flag)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions