golang/go
View on GitHubnet/http/httptrace: attaching a ClientTrace twice to the same context causes stack overflow
Open
#32,925 opened on Jul 3, 2019
NeedsInvestigationhelp wanted
Repository metrics
- Stars
- (133,883 stars)
- PR merge metrics
- (No merged PRs in 30d)
Description
What version of Go are you using (go version)?
Does this issue reproduce with the latest release?
Yes
What did you do?
package main
import (
"log"
"net/http"
"net/http/httptrace"
)
func main() {
tracer := &httptrace.ClientTrace{
ConnectStart: func(network, addr string) {
log.Println("traced")
},
}
req, err := http.NewRequest("GET", "http://localhost:9999/hello", nil)
if err != nil {
log.Printf("error creating request %v", err)
}
// Adding the same trace twice causes a stack overflow.
req = req.WithContext(httptrace.WithClientTrace(req.Context(), tracer))
req = req.WithContext(httptrace.WithClientTrace(req.Context(), tracer))
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
log.Printf("request error: %v", err)
}
if res != nil && res.Body != nil {
res.Body.Close()
}
}
What did you expect to see?
"traced" gets printed twice, and then a request error because nothing is listening on localhost:9999.
What did you see instead?
The stack overflows.
What I'm doing is silly, but it happened in production for a service due to a lot of indirection on retries and attempting to use a single tracer object for all traces.
The bug seems to be here https://github.com/golang/go/blob/b412fde53a6b53475e25aaa9e49f3c6df3c48716/src/net/http/httptrace/trace.go#L202-L204
Since *t and *old are the same, the of.Call() ends up calling itself.