Skip to content

Commit 52fcff3

Browse files
Jan Merclbradfitz
authored andcommitted
go/token: Fix race in FileSet.PositionFor.
Methods of FileSet are documented to be safe for concurrent use by multiple goroutines, so FileSet is protected by a mutex and all its methods use it to prevent concurrent mutations. All methods of File that mutate the respective FileSet, including AddLine, do also lock its mutex, but that does not help when PositionFor is invoked concurrently and reads without synchronization what AddLine mutates. The change adds acquiring a RLock around the racy call of File.position and the respective test. Fixes golang#16548 Change-Id: Iecaaa02630b2532cb29ab555376633ee862315dd Reviewed-on: https://go-review.googlesource.com/25345 Reviewed-by: Robert Griesemer <gri@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
1 parent 14e446d commit 52fcff3

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

src/go/token/position.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,9 @@ func (s *FileSet) File(p Pos) (f *File) {
446446
func (s *FileSet) PositionFor(p Pos, adjusted bool) (pos Position) {
447447
if p != NoPos {
448448
if f := s.file(p); f != nil {
449+
s.mutex.RLock()
449450
pos = f.position(p, adjusted)
451+
s.mutex.RUnlock()
450452
}
451453
}
452454
return

src/go/token/position_test.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ func TestFileSetCacheUnlikely(t *testing.T) {
214214
}
215215
}
216216

217-
// issue 4345. Test concurrent use of FileSet.Pos does not trigger a
217+
// issue 4345. Test that concurrent use of FileSet.Pos does not trigger a
218218
// race in the FileSet position cache.
219219
func TestFileSetRace(t *testing.T) {
220220
fset := NewFileSet()
@@ -237,6 +237,35 @@ func TestFileSetRace(t *testing.T) {
237237
stop.Wait()
238238
}
239239

240+
// issue 16548. Test that concurrent use of File.AddLine and FileSet.PositionFor
241+
// does not trigger a race in the FileSet position cache.
242+
func TestFileSetRace2(t *testing.T) {
243+
const N = 1e3
244+
var (
245+
fset = NewFileSet()
246+
file = fset.AddFile("", -1, N)
247+
ch = make(chan int, 2)
248+
)
249+
250+
go func() {
251+
for i := 0; i < N; i++ {
252+
file.AddLine(i)
253+
}
254+
ch <- 1
255+
}()
256+
257+
go func() {
258+
pos := file.Pos(0)
259+
for i := 0; i < N; i++ {
260+
fset.PositionFor(pos, false)
261+
}
262+
ch <- 1
263+
}()
264+
265+
<-ch
266+
<-ch
267+
}
268+
240269
func TestPositionFor(t *testing.T) {
241270
src := []byte(`
242271
foo

0 commit comments

Comments
 (0)