(*http.Transport).getConn currently starts a dialConn call in a background goroutine:
|
go func() { |
|
pc, err := t.dialConn(ctx, cm) |
|
dialc <- dialRes{pc, err} |
|
}() |
That records traces to the provided Context and eventually invokes t.DialContext with it:
|
trace := httptrace.ContextClientTrace(ctx) |
|
conn, err := t.dial(ctx, "tcp", cm.addr()) |
This is pretty much a textbook illustration of the problem described in #19643 (Context API for continuing work). If (*Transport).getConn returns early (due to cancellation or to availability of an idle connection), the caller may have already written out the corresponding traces, and dialConn (and/or the user-provided DialContext callback) will unexpectedly access a Context that the caller believes to be unreachable.
httptrace.ClientTrace says, "Functions may be called concurrently from different goroutines and some may be called after the request has completed or failed." However, that is not true of Context instances in general: if the http package wants to save a trace after a call has returned, it should call Value ahead of time and save only the ClientTrace pointer. If dialConn calls a user-provided DialContext function, then getConn should cancel the Context passed to it and wait for DialContext to return before itself returning.
See also #20617 (Context race in http.Transport).
(*http.Transport).getConncurrently starts adialConncall in a background goroutine:go/src/net/http/transport.go
Lines 942 to 945 in 0b0cc41
That records traces to the provided
Contextand eventually invokest.DialContextwith it:go/src/net/http/transport.go
Line 1029 in 0b0cc41
go/src/net/http/transport.go
Line 1060 in 0b0cc41
This is pretty much a textbook illustration of the problem described in #19643 (Context API for continuing work). If
(*Transport).getConnreturns early (due to cancellation or to availability of an idle connection), the caller may have already written out the corresponding traces, anddialConn(and/or the user-providedDialContextcallback) will unexpectedly access aContextthat the caller believes to be unreachable.httptrace.ClientTracesays, "Functions may be called concurrently from different goroutines and some may be called after the request has completed or failed." However, that is not true ofContextinstances in general: if thehttppackage wants to save a trace after a call has returned, it should callValueahead of time and save only theClientTracepointer. IfdialConncalls a user-providedDialContextfunction, thengetConnshould cancel theContextpassed to it and wait forDialContextto return before itself returning.See also #20617 (Context race in
http.Transport).