Skip to content

Commit 78c3585

Browse files
authored
cmd/anubis: Fix potential decaymap race (#683)
Fixes a potential TOCTOU issue that would cause values to be spuriously erased. IIUC, the following interleaving of (*DecayMap).Get() and (*DecayMap).Set() can cause an update to be erased: // thread A: Get("x") m.lock.RLock() value, ok := m.data["x"] m.lock.RUnlock() ... if time.Now().After(value.expiry) { // <wait for lock!> // thread B: Set("x", ...) m.lock.Lock() defer m.lock.Unlock() m.data["x"] = DecayMapEntry{ ... } // thread A continues its Get("x") after acquring the lock: m.lock.Lock() delete(m.data, "x") // Oops! Newer entry is deleted! m.lock.Unlock() Realistically... I think it's probably a non-issue either way, because the worst that can happen is that a cache entry is spuriously removed, and it'll just get re-fetched.
1 parent 8c30339 commit 78c3585

File tree

1 file changed

+5
-1
lines changed

1 file changed

+5
-1
lines changed

cmd/anubis/decaymap.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ func (m *DecayMap[K, V]) Get(key K) (V, bool) {
3737

3838
if time.Now().After(value.expiry) {
3939
m.lock.Lock()
40-
delete(m.data, key)
40+
// Since previously reading m.data[key], the value may have been updated.
41+
// Delete the entry only if the expiry time is still the same.
42+
if m.data[key].expiry == value.expiry {
43+
delete(m.data, key)
44+
}
4145
m.lock.Unlock()
4246

4347
return zilch[V](), false

0 commit comments

Comments
 (0)