Skip to content

Protect NewFilenameUnadjuster from concurrent map writes #1192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions pkg/result/processors/filename_unadjuster.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import (

type posMapper func(pos token.Position) token.Position

type adjustMap struct {
sync.Mutex
m map[string]posMapper
}

// FilenameUnadjuster is needed because a lot of linters use fset.Position(f.Pos())
// to get filename. And they return adjusted filename (e.g. *.qtpl) for an issue. We need
// restore real .go filename to properly output it, parse it, etc.
Expand All @@ -27,7 +32,7 @@ type FilenameUnadjuster struct {

var _ Processor = &FilenameUnadjuster{}

func processUnadjusterPkg(m map[string]posMapper, pkg *packages.Package, log logutils.Log) {
func processUnadjusterPkg(m *adjustMap, pkg *packages.Package, log logutils.Log) {
fset := token.NewFileSet() // it's more memory efficient to not store all in one fset

for _, filename := range pkg.CompiledGoFiles {
Expand All @@ -36,7 +41,7 @@ func processUnadjusterPkg(m map[string]posMapper, pkg *packages.Package, log log
}
}

func processUnadjusterFile(filename string, m map[string]posMapper, log logutils.Log, fset *token.FileSet) {
func processUnadjusterFile(filename string, m *adjustMap, log logutils.Log, fset *token.FileSet) {
syntax, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
if err != nil {
// Error will be reported by typecheck
Expand All @@ -57,7 +62,9 @@ func processUnadjusterFile(filename string, m map[string]posMapper, log logutils
return // file.go -> /caches/cgo-xxx
}

m[adjustedFilename] = func(adjustedPos token.Position) token.Position {
m.Lock()
defer m.Unlock()
m.m[adjustedFilename] = func(adjustedPos token.Position) token.Position {
tokenFile := fset.File(syntax.Pos())
if tokenFile == nil {
log.Warnf("Failed to get token file for %s", adjustedFilename)
Expand All @@ -68,22 +75,23 @@ func processUnadjusterFile(filename string, m map[string]posMapper, log logutils
}

func NewFilenameUnadjuster(pkgs []*packages.Package, log logutils.Log) *FilenameUnadjuster {
m := map[string]posMapper{}
m := adjustMap{m: map[string]posMapper{}}

startedAt := time.Now()
var wg sync.WaitGroup
wg.Add(len(pkgs))
for _, pkg := range pkgs {
go func(pkg *packages.Package) {
// It's important to call func here to run GC
processUnadjusterPkg(m, pkg, log)
processUnadjusterPkg(&m, pkg, log)
wg.Done()
}(pkg)
}
wg.Wait()
log.Infof("Pre-built %d adjustments in %s", len(m), time.Since(startedAt))
log.Infof("Pre-built %d adjustments in %s", len(m.m), time.Since(startedAt))

return &FilenameUnadjuster{
m: m,
m: m.m,
log: log,
loggedUnadjustments: map[string]bool{},
}
Expand Down