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/