2019年11月21日,golang的官方github倉庫提交了一個https://github.com/golang/go/issues/35750,該issue指出如果初始化 http.Server 結構體時指定了一個非空的 ConnContext 成員函數,且如果在該函數內使用了 context.Value 方法寫入數據到上下文並返回,則 Context 將會以鏈表的方式泄漏。
據官方開發人員表示,該bug於1.13版本引進,目前已經在1.13.5修復。
ConnContext
ConnContext optionally specifies a function that modifies the context used for a new connection c.
ConnContext是用於更改新連接的context而設置的一個方法。然而,它把新context賦值給了被所有連接共享的一個變量。
代碼如下:
type Server struct {
...
// ConnContext optionally specifies a function that modifies
// the context used for a new connection c. The provided ctx
// is derived from the base context and has a ServerContextKey
// value.
ConnContext func(ctx context.Context, c net.Conn) context.Context
...
}
func (srv *Server) Serve(l net.Listener) error {
...
baseCtx := context.Background()
...
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
rw, e := l.Accept()
...
if cc := srv.ConnContext; cc != nil {
ctx = cc(ctx, rw)
if ctx == nil {
panic("ConnContext returned nil")
}
}
...
go c.serve(ctx)
}
}
問題出在ctx = cc(ctx, rw)
,這一行錯誤的將cc
方法生成的新context賦值給了全局的ctx
變量。
修復方式
pull request diff 如下:
總結
通過此bug來看,對於開源代碼,在使用之前還是應該瞭解其實現細節,即使是github的明星項目(甚至go官方sdk)都不能盲目相信。
參考來源:
- https://github.com/golang/go/issues/35750
- https://go-review.googlesource.com/c/go/+/208318/