Bug Description
There is a data race on the source.refresh field in sources.go. The time.Time value is written at lines 180, 185, and 211 without holding the source lock, while PrefetchSources() reads it at line 267 without any synchronization.
Affected Code
sources.go:180 (in fetchWithCache):
source.refresh = now.Add(ttl) // write without lock
sources.go:267 (in PrefetchSources):
if source.refresh.IsZero() || source.refresh.After(now) { // read without lock
continue
}
Impact
time.Time is a 16-byte struct on 64-bit platforms. Concurrent write and read without synchronization is undefined behavior in Go's memory model. A partially written value could cause IsZero() or After() to read corrupted bytes, leading to incorrect prefetch scheduling or missed source updates.
Fix
Wrap writes in the source lock:
source.Lock()
source.refresh = now.Add(ttl)
source.Unlock()
And reads:
source.RLock()
needsRefresh := source.refresh.IsZero() || !source.refresh.After(now)
source.RUnlock()
Bug Description
There is a data race on the
source.refreshfield insources.go. Thetime.Timevalue is written at lines 180, 185, and 211 without holding the source lock, whilePrefetchSources()reads it at line 267 without any synchronization.Affected Code
sources.go:180(infetchWithCache):sources.go:267(inPrefetchSources):Impact
time.Timeis a 16-byte struct on 64-bit platforms. Concurrent write and read without synchronization is undefined behavior in Go's memory model. A partially written value could causeIsZero()orAfter()to read corrupted bytes, leading to incorrect prefetch scheduling or missed source updates.Fix
Wrap writes in the source lock:
And reads: