diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2023-07-23 13:55:51 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-23 13:55:51 +1000 |
commit | 1b05ba252c7e5ff2725b41ca2643c61b9ed84979 (patch) | |
tree | 83751e1811b1c147f99a958cbc3d09ad554f0144 | |
parent | 6f13b422799297d5f167ed3a24590f5e44eced0c (diff) | |
parent | 28474b08eeda872d67227ebc09f8a873e2bf2aad (diff) |
Fix crash caused by simultaneous read/write of scanner buffer (#2813)v0.39.3
-rw-r--r-- | pkg/tasks/tasks.go | 19 |
1 files 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 |