From 12358104ef0e5418a9636a552a7cc6902309adda Mon Sep 17 00:00:00 2001 From: Larry Clapp Date: Wed, 20 Mar 2024 17:40:56 -0400 Subject: [PATCH] Fix the data race under Linux Make sure the cancelreader Read & Close don't overlap. --- interp/builtin.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/interp/builtin.go b/interp/builtin.go index 57b2c85b..0342a7f0 100644 --- a/interp/builtin.go +++ b/interp/builtin.go @@ -13,6 +13,7 @@ import ( "path/filepath" "strconv" "strings" + "sync" "github.com/muesli/cancelreader" "mvdan.cc/sh/v3/expand" @@ -935,16 +936,26 @@ func (r *Runner) readLine(ctx context.Context, raw bool) ([]byte, error) { return nil, err } stdin = cr - done := make(chan bool) + done := make(chan struct{}) + var wg sync.WaitGroup + wg.Add(1) go func() { select { case <-ctx.Done(): cr.Cancel() case <-done: } + wg.Done() + }() + defer func() { + close(done) + wg.Wait() + // Could put the Close in the above goroutine, but if "read" is + // immediately called again, the Close might overlap with creating a + // new cancelreader. Want this cancelreader to be completely closed + // by the time readLine returns. cr.Close() }() - defer close(done) } for {