Lock the view while reading viewLines on mouse move

onMouseMove (and findHyperlinkAt, which it calls) read v.viewLines without
holding writeMutex, unlike every other reader. They run on the event-handling
goroutine, so a re-render on the task goroutine can shrink or rebuild viewLines
between onMouseMove's bounds check and findHyperlinkAt's indexing, causing an
out-of-range panic (observed: "index out of range [60] with length 0" while
hovering during a diff re-render).

Take writeMutex for the duration, like the other viewLines readers do, so the
check and the access see the same slice. Pre-existing, but the off-screen
re-render rebuilds viewLines on the task goroutine more often, widening the window.
This commit is contained in:
Stefan Haller 2026-06-10 11:11:21 +02:00
parent 35c3bbdee5
commit af147d49f7

View file

@ -2414,6 +2414,14 @@ func (v *View) onMouseMove(x int, y int) {
return
}
// Reading v.viewLines (here and in findHyperlinkAt) must hold writeMutex like
// every other reader: this runs on the event-handling goroutine, and a
// concurrent re-render on the task goroutine can rebuild or shrink viewLines
// between the bounds check below and the indexing in findHyperlinkAt — which
// panicked with an out-of-range index.
v.writeMutex.Lock()
defer v.writeMutex.Unlock()
// newCx and newCy are relative to the view port, i.e. to the visible area of the view
newCx := x - v.x0 - 1
newCy := y - v.y0 - 1