Closed
Description
(*ClientConn).encodeTrailers
encodes into a per-conn buffer (cc.hbuf
). Trailers are encoded with cc.mu
held, but written with only cc.wmu
held. If another request on the same ClientConn
uses the buffer while the trailers are being written, a race occurs.
https://go.googlesource.com/net/+/refs/heads/master/http2/transport.go#1417
Reproduction below.
func TestTransportFrameBufferReuse(t *testing.T) {
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {}, optOnlyServer)
defer st.Close()
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
defer tr.CloseIdleConnections()
filler := hex.EncodeToString([]byte(randString(2048)))
var wg sync.WaitGroup
defer wg.Wait()
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
req, err := http.NewRequest("POST", st.ts.URL, strings.NewReader(filler))
if err != nil {
t.Fatal(err)
}
req.Header.Set("Big", filler)
req.Trailer = make(http.Header)
req.Trailer.Set("Big", filler)
res, err := tr.RoundTrip(req)
if err != nil {
t.Fatal(err)
}
if got, want := res.StatusCode, 200; got != want {
t.Errorf("StatusCode = %v; want %v", got, want)
}
if res != nil && res.Body != nil {
res.Body.Close()
}
}()
}
}