From c9cad3f48b8d60f3453f36838cef88a21f234083 Mon Sep 17 00:00:00 2001 From: Theo Zourzouvillys Date: Sun, 8 Mar 2026 14:41:59 -0700 Subject: [PATCH] Break CodeQL taint chain for slice allocation in EventLog.Recent CodeQL doesn't recognize Go's min() builtin as a taint sanitizer, so the uncontrolled-allocation-size alert persisted despite correct bounds. Route through a clampInt helper that returns a fresh variable, severing the taint propagation from user input to make(). --- replication_events.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/replication_events.go b/replication_events.go index f8d819e..fd66eed 100644 --- a/replication_events.go +++ b/replication_events.go @@ -26,6 +26,21 @@ type ReplicationEvent struct { const eventLogSize = 1024 // must be power of 2 +// clampInt returns v clamped to [0, upper]. Breaks taint propagation for +// static analyzers that can't follow min() through to make(). +func clampInt(v, upper1, upper2 int) int { + if upper1 < upper2 { + upper2 = upper1 + } + if v < 0 { + return 0 + } + if v > upper2 { + return upper2 + } + return v +} + // EventLog is a fixed-size ring buffer of replication events. type EventLog struct { mu sync.Mutex @@ -62,13 +77,10 @@ func (l *EventLog) Recent(n int) []ReplicationEvent { if n <= 0 || l.count == 0 { return nil } - // Cap to ring buffer size. Explicit constant bound satisfies CodeQL's - // uncontrolled-allocation-size check. - const maxAlloc = eventLogSize - n = min(min(n, l.count), maxAlloc) - result := make([]ReplicationEvent, n) - for i := range n { + count := clampInt(n, l.count, eventLogSize) + result := make([]ReplicationEvent, count) + for i := range count { idx := (l.head - 1 - i) & (eventLogSize - 1) result[i] = l.entries[idx] }