From 3d60cac760fc5018ba4a1c728f1a513d24b8a075 Mon Sep 17 00:00:00 2001 From: Travis Turner Date: Sun, 11 Feb 2018 21:21:48 -0600 Subject: [PATCH] fixes a shift logic bug in bitmapZeroRange that was causing an overflow-like condition --- roaring/roaring.go | 2 +- roaring/roaring_internal_test.go | 86 ++++++++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index f98eea0eb..fc01b3783 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -2305,7 +2305,7 @@ func (c *container) bitmapZeroRange(i, j uint64) { x := i >> 6 y := (j - 1) >> 6 var X uint64 = maxBitmap << (i % 64) - var Y uint64 = maxBitmap >> (64 - (j % 64)) + var Y uint64 = maxBitmap >> (63 - ((j - 1) % 64)) if x == y { c.n -= int(popcnt(c.bitmap[x] & (X & Y))) c.bitmap[x] &= ^(X & Y) diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 825fdf0ae..8ce9ba9c1 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -1593,14 +1593,69 @@ func TestDifferenceBitmapRun(t *testing.T) { runs: []interval16{{start: 4, last: 7}, {start: 32, last: 47}}, exp: []uint64{0xFFFF0000FFFFFF0F}, }, + { + bitmap: []uint64{0xFFFFFFFFFFFFFFBF}, + runs: []interval16{{start: 0, last: 5}, {start: 7, last: 63}}, + exp: []uint64{0x0000000000000000}, + }, + { + bitmap: []uint64{0xFFFFFFFFFFFFFFBF}, + runs: []interval16{{start: 0, last: 5}}, + exp: []uint64{0xFFFFFFFFFFFFFF80}, + }, + { + bitmap: []uint64{0xFFFFFFFFFFFFFFFF}, + runs: []interval16{{start: 60, last: 63}}, + exp: []uint64{0x0FFFFFFFFFFFFFFF}, + }, + { + bitmap: []uint64{0xFFFFFFFFFFFFFFFF}, + runs: []interval16{{start: 60, last: 65}}, + exp: []uint64{0x0FFFFFFFFFFFFFFF}, + }, + { + bitmap: []uint64{0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + runs: []interval16{{start: 60, last: 65}, {start: 67, last: 72}, {start: 126, last: 130}}, + exp: []uint64{0x0FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFE04, 0xFFFFFFFFFFFFFFF8}, + }, + { + bitmap: []uint64{0x0000000000000001}, + runs: []interval16{{start: 0, last: 0}}, + exp: []uint64{0x0000000000000000}, + }, + { + bitmap: []uint64{0x8000000000000000}, + runs: []interval16{{start: 63, last: 63}}, + exp: []uint64{0x0000000000000000}, + }, + { + bitmap: []uint64{0xC000000000000000, 0x0000000000000003}, + runs: []interval16{{start: 63, last: 64}}, + exp: []uint64{0x4000000000000000, 0x0000000000000002}, + }, + { + bitmap: []uint64{0x0000000000000000}, + runs: []interval16{{start: 5, last: 7}}, + exp: []uint64{0x0000000000000000}, + }, + { + bitmap: bitmapLast(), + runs: []interval16{{start: 65535, last: 65535}}, + exp: bitmapEmpty(), + }, + { + bitmap: bitmapFull(), + runs: []interval16{{start: 0, last: 65535}}, + exp: bitmapEmpty(), + }, } for i, test := range tests { for i, v := range test.bitmap { a.bitmap[i] = v } - a.n = a.bitmapCountRange(0, 100) + a.n = a.bitmapCountRange(0, 65536) b.runs = test.runs - b.n = b.runCountRange(0, 100) + b.n = b.runCountRange(0, 65536) ret := differenceBitmapRun(a, b) if !reflect.DeepEqual(ret.bitmap[:len(test.exp)], test.exp) { t.Fatalf("test #%v expected \n%X, but got \n%X", i, test.exp, ret.bitmap[:len(test.exp)]) @@ -2497,7 +2552,7 @@ func Test_BufBitmapIterator_UnreadPanic(t *testing.T) { itr.unread() } -func TestSearc64(t *testing.T) { +func TestSearch64(t *testing.T) { tests := []struct { a []uint64 value uint64 @@ -2655,6 +2710,31 @@ func bitmapEvens() []uint64 { return bitmap } +func bitmapLast() []uint64 { + bitmap := make([]uint64, bitmapN) + for i := 0; i < bitmapN-1; i++ { + bitmap[i] = 0 + } + bitmap[bitmapN-1] = 0x8000000000000000 + return bitmap +} + +func bitmapFull() []uint64 { + bitmap := make([]uint64, bitmapN) + for i := 0; i < bitmapN; i++ { + bitmap[i] = 0xFFFFFFFFFFFFFFFF + } + return bitmap +} + +func bitmapEmpty() []uint64 { + bitmap := make([]uint64, bitmapN) + for i := 0; i < bitmapN; i++ { + bitmap[i] = 0 + } + return bitmap +} + var containerWidth uint64 = 65536 // rleCont returns a slice of numbers all in the range starting from