net/http: resolve data race in TestMaxBytesHandler

By the time handlerN and handlerErr are read by the main goroutine, the
server handler which writes to handlerN and handlerErr might still be
alive in HTTP/3 due to connection closure being asynchronous. Despite
the data race being logically impossible (when the main goroutine reads
handlerN and handlerErr, the server handler has definitely written the
response body and will no longer be writing to the contested variables),
this will trip off the race detector. As such, add a mutex to appease
the race detector.

For #70914

Change-Id: I453fdacf9056403886a789ee37023d126a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/771440
Reviewed-by: Nicholas Husin <husin@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
Nicholas S. Husin 2026-04-27 15:45:56 -04:00 committed by Nicholas Husin
parent f93915339a
commit a3f569adee

View file

@ -7117,7 +7117,6 @@ func testQuerySemicolon(t *testing.T, mode testMode, query string, wantX string,
}
}
// HTTP/3 trips off race detector.
func TestMaxBytesHandler(t *testing.T) {
// Not parallel: modifies the global rstAvoidanceDelay.
defer afterTest(t)
@ -7128,7 +7127,7 @@ func TestMaxBytesHandler(t *testing.T) {
func(t *testing.T) {
run(t, func(t *testing.T, mode testMode) {
testMaxBytesHandler(t, mode, maxSize, requestSize)
}, testNotParallel, http3SkippedMode)
}, testNotParallel)
})
}
}
@ -7149,10 +7148,13 @@ func testMaxBytesHandler(t *testing.T, mode testMode, maxSize, requestSize int64
t.Logf("set RST avoidance delay to %v", timeout)
var (
mu sync.Mutex // guards below
handlerN int64
handlerErr error
)
echo := HandlerFunc(func(w ResponseWriter, r *Request) {
mu.Lock()
defer mu.Unlock()
var buf bytes.Buffer
handlerN, handlerErr = io.Copy(&buf, r.Body)
io.Copy(w, &buf)
@ -7201,6 +7203,8 @@ func testMaxBytesHandler(t *testing.T, mode testMode, maxSize, requestSize int64
// to rstAvoidanceDelay being too short, so we use t.Errorf for those
// instead of returning a (retriable) error.
mu.Lock()
defer mu.Unlock()
if handlerN > maxSize {
t.Errorf("expected max request body %d; got %d", maxSize, handlerN)
}