Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ vortex-btrblocks = { workspace = true }
vortex-buffer = { workspace = true }
vortex-dtype = { workspace = true, features = ["arbitrary"] }
vortex-error = { workspace = true }
vortex-expr = { workspace = true, features = ["arbitrary"] }
vortex-file = { workspace = true }
vortex-mask = { workspace = true }
vortex-scalar = { workspace = true, features = ["arbitrary"] }
Expand Down
14 changes: 11 additions & 3 deletions fuzz/fuzz_targets/file_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,25 @@ use arrow_ord::sort::SortOptions;
use futures_util::TryStreamExt;
use libfuzzer_sys::{Corpus, fuzz_target};
use vortex_array::arrays::ChunkedArray;
use vortex_array::arrays::arbitrary::ArbitraryArray;
use vortex_array::arrow::IntoArrowArray;
use vortex_array::compute::{Operator, compare};
use vortex_array::{Array, ArrayRef, Canonical, IntoArray, ToCanonical};
use vortex_buffer::ByteBufferMut;
use vortex_dtype::{DType, StructFields};
use vortex_error::{VortexExpect, VortexUnwrap, vortex_panic};
use vortex_expr::root;
use vortex_file::{VortexOpenOptions, VortexWriteOptions};
use vortex_fuzz::FuzzFileAction;
use vortex_utils::aliases::DefaultHashBuilder;
use vortex_utils::aliases::hash_set::HashSet;

fuzz_target!(|array_data: ArbitraryArray| -> Corpus {
let array_data = array_data.0;
fuzz_target!(|fuzz: FuzzFileAction| -> Corpus {
let FuzzFileAction {
array,
projection,
filter,
} = fuzz;
let array_data = array;

if has_nullable_struct(array_data.dtype()) || has_duplicate_field_names(array_data.dtype()) {
return Corpus::Reject;
Expand All @@ -41,6 +47,8 @@ fuzz_target!(|array_data: ArbitraryArray| -> Corpus {
.vortex_unwrap()
.scan()
.vortex_unwrap()
.with_projection(projection.unwrap_or_else(|| root()))
.with_some_filter(filter)
.into_array_stream()
.vortex_unwrap()
.try_collect::<Vec<_>>()
Expand Down
21 changes: 21 additions & 0 deletions fuzz/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ use vortex_array::{Array, ArrayRef, IntoArray};
use vortex_btrblocks::BtrBlocksCompressor;
use vortex_dtype::{DType, Nullability};
use vortex_error::{VortexExpect, VortexUnwrap, vortex_panic};
use vortex_expr::ExprRef;
use vortex_expr::arbitrary::{filter_expr, projection_expr};
use vortex_mask::Mask;
use vortex_scalar::Scalar;
use vortex_scalar::arbitrary::random_scalar;
Expand Down Expand Up @@ -253,3 +255,22 @@ fn actions_for_dtype(dtype: &DType) -> HashSet<usize> {
_ => ALL_ACTIONS.collect(),
}
}

#[derive(Debug)]
pub struct FuzzFileAction {
pub array: ArrayRef,
pub projection: Option<ExprRef>,
pub filter: Option<ExprRef>,
}

impl<'a> Arbitrary<'a> for FuzzFileAction {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
let array = ArbitraryArray::arbitrary(u)?.0;
let dtype = array.dtype().clone();
Ok(FuzzFileAction {
array,
projection: projection_expr(u, &dtype)?,
filter: filter_expr(u, &dtype)?,
})
}
}
6 changes: 6 additions & 0 deletions vortex-expr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ version = { workspace = true }
workspace = true

[dependencies]
arbitrary = { workspace = true, optional = true }
dyn-hash = { workspace = true }
itertools = { workspace = true }
prost = { workspace = true, optional = true }
Expand All @@ -34,6 +35,11 @@ vortex-utils = { workspace = true }
vortex-expr = { path = ".", features = ["test-harness"] }

[features]
arbitrary = [
"dep:arbitrary",
"vortex-scalar/arbitrary",
"vortex-dtype/arbitrary",
]
serde = ["dep:serde", "vortex-dtype/serde", "vortex-error/serde"]
proto = ["vortex-proto/expr", "vortex-error/prost", "dep:prost", "serde"]
test-harness = []
63 changes: 63 additions & 0 deletions vortex-expr/src/arbitrary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use std::cmp::max;

use arbitrary::{Result as AResult, Unstructured};
use vortex_dtype::{DType, FieldName};
use vortex_scalar::arbitrary::random_scalar;

use crate::{BinaryExpr, ExprRef, Operator, and_collect, get_item_scope, lit, pack};

pub fn projection_expr(u: &mut Unstructured<'_>, dtype: &DType) -> AResult<Option<ExprRef>> {
let Some(struct_dtype) = dtype.as_struct() else {
return Ok(None);
};

let column_count = u.int_in_range::<usize>(0..=max(struct_dtype.nfields(), 10))?;

let cols = (0..column_count)
.map(|_| {
let get_item = u.choose(struct_dtype.names().iter().as_slice())?;
Ok((get_item.clone(), get_item_scope(get_item.clone())))
})
.collect::<AResult<Vec<_>>>()?;

Ok(Some(pack(cols, u.arbitrary()?)))
}

pub fn filter_expr(u: &mut Unstructured<'_>, dtype: &DType) -> AResult<Option<ExprRef>> {
let Some(struct_dtype) = dtype.as_struct() else {
return Ok(None);
};

let filter_count = u.int_in_range::<usize>(0..=max(struct_dtype.nfields(), 10))?;

let filters = (0..filter_count)
.map(|_| {
let (col, dtype) =
u.choose_iter(struct_dtype.names().iter().zip(struct_dtype.fields()))?;
random_comparison(u, col, &dtype)
})
.collect::<AResult<Vec<_>>>()?;

Ok(and_collect(filters))
}

fn random_comparison(u: &mut Unstructured<'_>, col: &FieldName, dtype: &DType) -> AResult<ExprRef> {
let scalar = random_scalar(u, dtype)?;
Ok(BinaryExpr::new_expr(
get_item_scope(col.clone()),
arbitrary_comparison_operator(u)?,
lit(scalar),
))
}

fn arbitrary_comparison_operator(u: &mut Unstructured<'_>) -> AResult<Operator> {
Ok(match u.int_in_range(0..=5)? {
0 => Operator::Eq,
1 => Operator::NotEq,
2 => Operator::Gt,
3 => Operator::Gte,
4 => Operator::Lt,
5 => Operator::Lte,
_ => unreachable!("range 0..=5"),
})
}
2 changes: 2 additions & 0 deletions vortex-expr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use dyn_hash::DynHash;
mod binary;

mod analysis;
#[cfg(feature = "arbitrary")]
pub mod arbitrary;
mod between;
mod cast;
mod field;
Expand Down
Loading