Skip to content

Data race on internalResolverReady field in xtransport.go #3205

Description

@hklcf

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
}(&registeredServers[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() {

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions