Bug Description
There is a data race on proxy.xTransport.internalResolverReady in serversInfo.go. Multiple goroutines (one per server, up to certRefreshConcurrency) concurrently write to the plain bool field without any synchronization.
Affected Code
serversInfo.go:264 (writer):
go func(registeredServer *RegisteredServer) {
err := serversInfo.refreshServer(proxy, registeredServer.name, registeredServer.stamp)
if err == nil {
proxy.xTransport.internalResolverReady = true // RACE
}
errorChannel <- err
<-countChannel
}(®isteredServers[i])
xtransport.go:562 (reader):
if xTransport.internalResolverReady {
Impact
While bool writes are often atomic in practice, Go's memory model does not guarantee visibility across goroutines without synchronization. A stale false value could cause the proxy to skip internal resolvers and fall through to bootstrap resolvers unnecessarily, or a stale true value could cause the proxy to use internal resolvers that aren't actually ready yet.
Fix
Use atomic.Bool from sync/atomic:
// Change declaration to:
internalResolverReady atomic.Bool
// Writer:
proxy.xTransport.internalResolverReady.Store(true)
// Reader:
if proxy.xTransport.internalResolverReady.Load() {
Bug Description
There is a data race on
proxy.xTransport.internalResolverReadyinserversInfo.go. Multiple goroutines (one per server, up tocertRefreshConcurrency) concurrently write to the plainboolfield without any synchronization.Affected Code
serversInfo.go:264(writer):xtransport.go:562(reader):Impact
While bool writes are often atomic in practice, Go's memory model does not guarantee visibility across goroutines without synchronization. A stale
falsevalue could cause the proxy to skip internal resolvers and fall through to bootstrap resolvers unnecessarily, or a staletruevalue could cause the proxy to use internal resolvers that aren't actually ready yet.Fix
Use
atomic.Boolfromsync/atomic: