Skip to content

Commit d9c476b

Browse files
committed
add fuzzing to the iterator
1 parent b02a94a commit d9c476b

File tree

3 files changed

+119
-2
lines changed

3 files changed

+119
-2
lines changed

fuzz/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fuzz/fuzz_targets/against_croaring.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ mod arbitrary_ops;
55
use libfuzzer_sys::arbitrary::{self, Arbitrary};
66
use libfuzzer_sys::fuzz_target;
77

8-
use crate::arbitrary_ops::{check_equal, Operation};
8+
use crate::arbitrary_ops::{check_equal, BitmapIteratorOperation, CRoaringIterRange, Operation};
99

1010
#[derive(Arbitrary, Debug)]
1111
struct FuzzInput<'a> {
1212
ops: Vec<Operation>,
13+
iter_ops: Vec<BitmapIteratorOperation>,
1314
initial_input: &'a [u8],
1415
}
1516

@@ -35,6 +36,14 @@ fuzz_target!(|input: FuzzInput| {
3536
}
3637
lhs_r.internal_validate().unwrap();
3738
rhs_r.internal_validate().unwrap();
39+
40+
let mut lhs_c_iter = CRoaringIterRange::new(&lhs_c);
41+
let mut lhs_r_iter = lhs_r.iter();
42+
43+
for op in input.iter_ops {
44+
op.apply(&mut lhs_c_iter, &mut lhs_r_iter);
45+
}
46+
3847
check_equal(&lhs_c, &lhs_r);
3948
check_equal(&rhs_c, &rhs_r);
4049
});

fuzz/fuzz_targets/arbitrary_ops/mod.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ pub enum BitmapBinaryOperation {
9595
AndNot,
9696
}
9797

98+
#[derive(Arbitrary, Debug)]
99+
pub enum BitmapIteratorOperation {
100+
Next,
101+
NextBack,
102+
AdvanceTo(Num),
103+
AdvanceBackTo(Num),
104+
Nth(Num),
105+
NthBack(Num),
106+
}
107+
98108
impl ReadBitmapOperation {
99109
pub fn apply(&self, x: &mut croaring::Bitmap, y: &mut roaring::RoaringBitmap) {
100110
match *self {
@@ -387,6 +397,104 @@ impl BitmapBinaryOperation {
387397
}
388398
}
389399

400+
pub struct CRoaringIterRange<'a> {
401+
cursor: croaring::bitmap::BitmapCursor<'a>,
402+
empty: bool,
403+
start: u32,
404+
end_inclusive: u32,
405+
}
406+
407+
impl<'a> CRoaringIterRange<'a> {
408+
pub fn new(bitmap: &'a croaring::Bitmap) -> Self {
409+
CRoaringIterRange {
410+
cursor: bitmap.cursor(),
411+
start: 0,
412+
end_inclusive: u32::MAX,
413+
empty: false,
414+
}
415+
}
416+
417+
fn next(&mut self) -> Option<u32> {
418+
if self.empty {
419+
return None;
420+
}
421+
self.cursor.reset_at_or_after(self.start);
422+
let res = self.cursor.current().filter(|&n| n <= self.end_inclusive);
423+
match res {
424+
None => self.empty = true,
425+
Some(n) if n == self.end_inclusive => self.empty = true,
426+
Some(n) => self.start = n + 1,
427+
}
428+
res
429+
}
430+
431+
fn next_back(&mut self) -> Option<u32> {
432+
if self.empty {
433+
return None;
434+
}
435+
self.cursor.reset_at_or_after(self.end_inclusive);
436+
if self.cursor.current().is_none_or(|n| n > self.end_inclusive) {
437+
self.cursor.move_prev();
438+
}
439+
let res = self.cursor.current().filter(|&n| n >= self.start);
440+
match res {
441+
None => self.empty = true,
442+
Some(n) if n == self.start => self.empty = true,
443+
Some(n) => self.end_inclusive = n - 1,
444+
}
445+
res
446+
}
447+
448+
fn advance_to(&mut self, num: u32) {
449+
self.start = self.start.max(num);
450+
}
451+
452+
fn advance_back_to(&mut self, num: u32) {
453+
self.end_inclusive = self.end_inclusive.min(num);
454+
}
455+
456+
fn nth(&mut self, num: u32) -> Option<u32> {
457+
for _ in 0..num {
458+
_ = self.next();
459+
}
460+
self.next()
461+
}
462+
463+
fn nth_back(&mut self, num: u32) -> Option<u32> {
464+
for _ in 0..num {
465+
_ = self.next_back();
466+
}
467+
self.next_back()
468+
}
469+
}
470+
471+
impl BitmapIteratorOperation {
472+
pub fn apply(&self, x: &mut CRoaringIterRange, y: &mut roaring::bitmap::Iter) {
473+
match *self {
474+
BitmapIteratorOperation::Next => {
475+
assert_eq!(x.next(), y.next());
476+
}
477+
BitmapIteratorOperation::NextBack => {
478+
assert_eq!(x.next_back(), y.next_back());
479+
}
480+
BitmapIteratorOperation::AdvanceTo(n) => {
481+
x.advance_to(n.0);
482+
y.advance_to(n.0);
483+
}
484+
BitmapIteratorOperation::AdvanceBackTo(n) => {
485+
x.advance_back_to(n.0);
486+
y.advance_back_to(n.0);
487+
}
488+
BitmapIteratorOperation::Nth(n) => {
489+
assert_eq!(x.nth(n.0), y.nth(n.0 as usize));
490+
}
491+
BitmapIteratorOperation::NthBack(n) => {
492+
assert_eq!(x.nth_back(n.0), y.nth_back(n.0 as usize));
493+
}
494+
}
495+
}
496+
}
497+
390498
pub(crate) fn check_equal(c: &croaring::Bitmap, r: &roaring::RoaringBitmap) {
391499
let mut lhs = c.iter();
392500
let mut rhs = r.iter();

0 commit comments

Comments
 (0)