Skip to content

Commit

Permalink
Initial work
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamGS committed Aug 15, 2024
1 parent 89c9e0f commit 47b2283
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 60 deletions.
8 changes: 6 additions & 2 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@
name = "vortex-fuzz"
version = "0.0.0"
publish = false
edition = "2021"
edition = { workspace = true }
license = { workspace = true }

[package.metadata]
cargo-fuzz = true

[dependencies]
libfuzzer-sys = "0.4"
libfuzzer-sys = { version = "0.4" }
vortex-array = { workspace = true, features = ["arbitrary"] }
vortex-dtype = { workspace = true }
vortex-sampling-compressor = { workspace = true }
vortex-scalar = { workspace = true }

[lib]
name = "vortex_fuzz"
path = "src/lib.rs"


[[bin]]
name = "fuzz_target_1"
Expand Down
74 changes: 16 additions & 58 deletions fuzz/fuzz_targets/fuzz_target_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,81 +2,39 @@

use std::collections::HashSet;

use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured};
use libfuzzer_sys::{fuzz_target, Corpus};
use vortex::compute::slice;
use vortex::compute::unary::scalar_at;
use vortex::encoding::EncodingId;
use vortex::Array;
use vortex_sampling_compressor::compressors::alp::ALPCompressor;
use vortex_sampling_compressor::compressors::bitpacked::BitPackedCompressor;
use vortex_sampling_compressor::compressors::dict::DictCompressor;
use vortex_sampling_compressor::compressors::r#for::FoRCompressor;
use vortex_sampling_compressor::compressors::roaring_bool::RoaringBoolCompressor;
use vortex_sampling_compressor::compressors::roaring_int::RoaringIntCompressor;
use vortex_sampling_compressor::compressors::runend::DEFAULT_RUN_END_COMPRESSOR;
use vortex_sampling_compressor::compressors::sparse::SparseCompressor;
use vortex_sampling_compressor::compressors::zigzag::ZigZagCompressor;
use vortex_fuzz::FuzzArrayAction;
use vortex_sampling_compressor::compressors::CompressorRef;
use vortex_sampling_compressor::SamplingCompressor;
use vortex_scalar::{PValue, Scalar, ScalarValue};

fuzz_target!(|data: &[u8]| -> Corpus {
let mut u = Unstructured::new(data);

let array = Array::arbitrary(&mut u).unwrap();
fuzz_target!(|fuzz_action: FuzzArrayAction| -> Corpus {
let FuzzArrayAction { array, action } = fuzz_action;

// TODO(adamg): We actually might want to test empty things, but I'm punting this issue for now
if array.is_empty() {
return Corpus::Reject;
};
match u.int_in_range(0..=9).unwrap() {
0 => {
let start = u.choose_index(array.len()).unwrap();
let stop = u.choose_index(array.len() - start).unwrap() + start;
let slice = slice(&array, start, stop).unwrap();
assert_slice(&array, &slice, start);
}
1 => match fuzz_compress(&array, &ALPCompressor) {
Some(compressed_array) => assert_array_eq(&array, &compressed_array),
None => return Corpus::Reject,
},
2 => match fuzz_compress(&array, &BitPackedCompressor) {
Some(compressed_array) => assert_array_eq(&array, &compressed_array),
None => return Corpus::Reject,
},
3 => match fuzz_compress(&array, &DictCompressor) {
Some(compressed_array) => assert_array_eq(&array, &compressed_array),
None => return Corpus::Reject,
},
4 => match fuzz_compress(&array, &FoRCompressor) {
Some(compressed_array) => assert_array_eq(&array, &compressed_array),
None => return Corpus::Reject,
},
5 => match fuzz_compress(&array, &RoaringBoolCompressor) {
Some(compressed_array) => assert_array_eq(&array, &compressed_array),
None => return Corpus::Reject,
},
6 => match fuzz_compress(&array, &RoaringIntCompressor) {
Some(compressed_array) => assert_array_eq(&array, &compressed_array),
None => return Corpus::Reject,
},
7 => match fuzz_compress(&array, &DEFAULT_RUN_END_COMPRESSOR) {
Some(compressed_array) => assert_array_eq(&array, &compressed_array),
None => return Corpus::Reject,
},
8 => match fuzz_compress(&array, &SparseCompressor) {
Some(compressed_array) => assert_array_eq(&array, &compressed_array),
None => return Corpus::Reject,
},
9 => match fuzz_compress(&array, &ZigZagCompressor) {
Some(compressed_array) => assert_array_eq(&array, &compressed_array),

match action {
vortex_fuzz::Action::Compress(c) => match fuzz_compress(&array, c.as_ref()) {
Some(compressed_array) => {
assert_array_eq(&array, &compressed_array);
Corpus::Keep
}
None => return Corpus::Reject,
},
_ => unreachable!(),
vortex_fuzz::Action::Slice(range) => {
let slice = slice(&array, range.start, range.end).unwrap();
assert_slice(&array, &slice, range.start);
Corpus::Keep
}
vortex_fuzz::Action::NoOp => Corpus::Reject,
}

Corpus::Keep
});

fn fuzz_compress(array: &Array, compressor_ref: CompressorRef<'_>) -> Option<Array> {
Expand Down
70 changes: 70 additions & 0 deletions fuzz/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::ops::Range;

use libfuzzer_sys::arbitrary::{Arbitrary, Result, Unstructured};
use vortex::Array;
use vortex_sampling_compressor::compressors::alp::ALPCompressor;
use vortex_sampling_compressor::compressors::bitpacked::BitPackedCompressor;
use vortex_sampling_compressor::compressors::dict::DictCompressor;
use vortex_sampling_compressor::compressors::r#for::FoRCompressor;
use vortex_sampling_compressor::compressors::roaring_bool::RoaringBoolCompressor;
use vortex_sampling_compressor::compressors::roaring_int::RoaringIntCompressor;
use vortex_sampling_compressor::compressors::runend::DEFAULT_RUN_END_COMPRESSOR;
use vortex_sampling_compressor::compressors::sparse::SparseCompressor;
use vortex_sampling_compressor::compressors::zigzag::ZigZagCompressor;
use vortex_sampling_compressor::compressors::EncodingCompressor;

pub struct FuzzArrayAction {
pub array: Array,
pub action: Action,
}

impl std::fmt::Debug for FuzzArrayAction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FuzzArrayAction")
.field("action", &self.action)
.field("array", &self.array)
.finish()
}
}

#[derive()]
pub enum Action {
NoOp,
Compress(Box<dyn EncodingCompressor>),
Slice(Range<usize>),
}

impl std::fmt::Debug for Action {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NoOp => write!(f, "NoOp"),
Self::Slice(arg0) => f.debug_tuple("Slice").field(arg0).finish(),
Self::Compress(c) => write!(f, "Compress({})", c.id()),
}
}
}

impl<'a> Arbitrary<'a> for FuzzArrayAction {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
let array = Array::arbitrary(u)?;
let action = match u.int_in_range(0..=9)? {
0 => {
let start = u.choose_index(array.len())?;
let stop = u.choose_index(array.len() - start).unwrap() + start;
Action::Slice(start..stop)
}
1 => Action::Compress(Box::new(ALPCompressor) as _),
2 => Action::Compress(Box::new(BitPackedCompressor) as _),
3 => Action::Compress(Box::new(DictCompressor) as _),
4 => Action::Compress(Box::new(FoRCompressor) as _),
5 => Action::Compress(Box::new(RoaringBoolCompressor) as _),
6 => Action::Compress(Box::new(RoaringIntCompressor) as _),
7 => Action::Compress(Box::new(DEFAULT_RUN_END_COMPRESSOR) as _),
8 => Action::Compress(Box::new(SparseCompressor) as _),
9 => Action::Compress(Box::new(ZigZagCompressor) as _),
_ => Action::NoOp,
};

Ok(Self { array, action })
}
}

0 comments on commit 47b2283

Please sign in to comment.