From 28474b08eeda872d67227ebc09f8a873e2bf2aad Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 23 Jul 2023 13:06:28 +1000 Subject: Fix crash caused by simultaneous read/write of scanner buffer --- pkg/tasks/tasks.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index 8fcebf4b4..88ce3cfce 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -164,7 +164,8 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p scanner := bufio.NewScanner(r) scanner.Split(bufio.ScanLines) - data := make(chan []byte) + lineChan := make(chan []byte) + lineWrittenChan := make(chan struct{}) // We're reading from the scanner in a separate goroutine because on windows // if running git through a shim, we sometimes kill the parent process without @@ -172,10 +173,18 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p // leaves us with a dead goroutine, but it's better than blocking all // rendering to main views. go utils.Safe(func() { + defer close(lineChan) for scanner.Scan() { - data <- scanner.Bytes() + select { + case <-opts.Stop: + return + case lineChan <- scanner.Bytes(): + // We need to confirm the data has been fed into the view before we + // pull more from the scanner because the scanner uses the same backing + // array and we don't want to be mutating that while it's being written + <-lineWrittenChan + } } - close(data) }) loaded := false @@ -222,7 +231,7 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p select { case <-opts.Stop: break outer - case line, ok = <-data: + case line, ok = <-lineChan: break } @@ -243,6 +252,7 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p break outer } writeToView(append(line, '\n')) + lineWrittenChan <- struct{}{} if i+1 == linesToRead.InitialRefreshAfter { // We have read enough lines to fill the view, so do a first refresh @@ -269,6 +279,7 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p onDone() close(done) + close(lineWrittenChan) }) self.readLines <- linesToRead -- cgit v1.2.3