From b8e517b35b6e7115a4cd761d25ce0e072ff9ab22 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:59:41 +0000 Subject: [PATCH] Fix data race in expandConnections: remove orphaned waitForCompletion goroutine The go f.waitForCompletion() goroutine in expandConnections was redundant since the downloadLoop's slow start loop already handles stateSteady by calling waitForCompletion directly. The orphaned goroutine could race with doStart() when writing f.ctx during pause/resume. Co-authored-by: monkeyWie <13160176+monkeyWie@users.noreply.github.com> --- internal/protocol/http/fetcher.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/protocol/http/fetcher.go b/internal/protocol/http/fetcher.go index 5bf305d7..1b45cf84 100644 --- a/internal/protocol/http/fetcher.go +++ b/internal/protocol/http/fetcher.go @@ -872,9 +872,9 @@ func (f *Fetcher) expandConnections() { f.connMu.Unlock() if len(newConns) == 0 { - // No new connections could be created, stop expansion + // No new connections could be created, stop expansion. + // The downloadLoop will check stateSteady and call waitForCompletion. f.setState(stateSteady) - go f.waitForCompletion() return } @@ -1195,9 +1195,9 @@ func (f *Fetcher) runConnectionWithResolveResp(conn *connection) { if n > 0 { // For non-range downloads with known size, enforce size limit if !f.meta.Res.Range && f.meta.Res.Size > 0 { + f.connMu.Lock() remaining := f.meta.Res.Size - conn.Downloaded if remaining <= 0 { - f.connMu.Lock() conn.Completed = true conn.State = connCompleted f.connMu.Unlock() @@ -1206,6 +1206,7 @@ func (f *Fetcher) runConnectionWithResolveResp(conn *connection) { if remaining < int64(n) { n = int(remaining) } + f.connMu.Unlock() } f.fileMu.Lock() @@ -1225,17 +1226,18 @@ func (f *Fetcher) runConnectionWithResolveResp(conn *connection) { } f.fileMu.Unlock() + f.connMu.Lock() conn.Chunk.Downloaded += int64(n) conn.Downloaded += int64(n) // Check if size limit reached after updating counters if !f.meta.Res.Range && f.meta.Res.Size > 0 && conn.Downloaded >= f.meta.Res.Size { - f.connMu.Lock() conn.Completed = true conn.State = connCompleted f.connMu.Unlock() return } + f.connMu.Unlock() } if err != nil { if err == io.EOF {