Skip to content

Commit 60ea6a7

Browse files
committed
fix: Ranges() infinite loop on bitmap containers and hs|offset overflow
Two bugs in Ranges(): 1. bitmapContainer: after emitting a short run within a 64-bit word, pos was recalculated via integer division back to the same word, causing an infinite loop. Fix: process all runs within a word using an inner loop that clears processed bits. 2. bitmapContainer + arrayContainer used hs|offset instead of hs+offset to combine the container key with local offsets. This silently produced wrong endExclusive values for the last container (key 0xFFFF) where the exclusive end (65536) overflows into the key bits. The runContainer16 path already used + correctly.
1 parent 6d1c0c8 commit 60ea6a7

File tree

2 files changed

+680
-54
lines changed

2 files changed

+680
-54
lines changed

iter.go

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,36 +92,43 @@ func (b *Bitmap) Ranges() iter.Seq2[uint32, uint64] {
9292
pos := uint(0)
9393

9494
for pos < length {
95-
if bm[pos] == 0 {
95+
w := bm[pos]
96+
if w == 0 {
9697
pos++
9798
continue
9899
}
99100

100-
w := bm[pos]
101-
lo := uint(countTrailingZeros(w))
102-
bitStart := pos*64 + lo
101+
for w != 0 {
102+
lo := uint(countTrailingZeros(w))
103+
bitStart := pos*64 + lo
103104

104-
ones := uint(countTrailingOnes(w >> lo))
105-
if lo+ones < 64 {
106-
if !emit(hs|uint64(bitStart), hs|uint64(bitStart+ones)) {
107-
return
108-
}
109-
pos = (bitStart + ones) / 64
110-
} else {
111-
pos++
112-
for pos < length && bm[pos] == 0xFFFFFFFFFFFFFFFF {
113-
pos++
114-
}
115-
var bitEnd uint
116-
if pos < length {
117-
bitEnd = pos*64 + uint(countTrailingOnes(bm[pos]))
105+
ones := uint(countTrailingOnes(w >> lo))
106+
if lo+ones < 64 {
107+
if !emit(hs+uint64(bitStart), hs+uint64(bitStart+ones)) {
108+
return
109+
}
110+
w &= ^((uint64(1) << (lo + ones)) - 1)
118111
} else {
119-
bitEnd = length * 64
120-
}
121-
if !emit(hs|uint64(bitStart), hs|uint64(bitEnd)) {
122-
return
112+
pos++
113+
for pos < length && bm[pos] == 0xFFFFFFFFFFFFFFFF {
114+
pos++
115+
}
116+
var bitEnd uint
117+
if pos < length {
118+
trailing := uint(countTrailingOnes(bm[pos]))
119+
bitEnd = pos*64 + trailing
120+
w = bm[pos] & ^((uint64(1) << trailing) - 1)
121+
} else {
122+
bitEnd = length * 64
123+
w = 0
124+
}
125+
if !emit(hs+uint64(bitStart), hs+uint64(bitEnd)) {
126+
return
127+
}
128+
continue
123129
}
124130
}
131+
pos++
125132
}
126133

127134
case *arrayContainer:
@@ -135,7 +142,7 @@ func (b *Bitmap) Ranges() iter.Seq2[uint32, uint64] {
135142
end++
136143
i++
137144
}
138-
if !emit(hs|start, hs|end) {
145+
if !emit(hs+start, hs+end) {
139146
return
140147
}
141148
}

0 commit comments

Comments
 (0)