Limit the type hierarchies in component fuzzing (#4668)
* Limit the type hierarchies in component fuzzing For now `wasmparser` has a hard limit on the size of tuples and such at 1000 recursive types within the tuple itself. Respect this limit by limiting the width of recursive types generated for the `component_api` fuzzer. This commit unifies this new requirement with the preexisting `TupleArray` and `NonEmptyArray` types into one `VecInRange<T, L, H>` which allow expressing all of these various requirements in one type. * Fix a compile error on `main` * Review comments
This commit is contained in:
@@ -25,10 +25,6 @@ pub const IMPORT_FUNCTION: &str = "echo";
|
|||||||
/// The name of the exported guest function which the host should call
|
/// The name of the exported guest function which the host should call
|
||||||
pub const EXPORT_FUNCTION: &str = "echo";
|
pub const EXPORT_FUNCTION: &str = "echo";
|
||||||
|
|
||||||
/// Maximum length of an arbitrary tuple type. As of this writing, the `wasmtime::component::func::typed` module
|
|
||||||
/// only implements the `ComponentType` trait for tuples up to this length.
|
|
||||||
const MAX_TUPLE_LENGTH: usize = 16;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
enum CoreType {
|
enum CoreType {
|
||||||
I32,
|
I32,
|
||||||
@@ -76,45 +72,23 @@ impl<'a, const L: usize, const H: usize> Arbitrary<'a> for UsizeInRange<L, H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps a `Box<[T]>` and provides an `Arbitrary` implementation that always generates non-empty slices
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct NonEmptyArray<T>(Box<[T]>);
|
|
||||||
|
|
||||||
impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for NonEmptyArray<T> {
|
|
||||||
fn arbitrary(input: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
|
||||||
Ok(Self(
|
|
||||||
iter::once(input.arbitrary())
|
|
||||||
.chain(input.arbitrary_iter()?)
|
|
||||||
.collect::<arbitrary::Result<_>>()?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Deref for NonEmptyArray<T> {
|
|
||||||
type Target = [T];
|
|
||||||
|
|
||||||
fn deref(&self) -> &[T] {
|
|
||||||
self.0.deref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wraps a `Box<[T]>` and provides an `Arbitrary` implementation that always generates slices of length less than
|
/// Wraps a `Box<[T]>` and provides an `Arbitrary` implementation that always generates slices of length less than
|
||||||
/// or equal to the longest tuple for which Wasmtime generates a `ComponentType` impl
|
/// or equal to the longest tuple for which Wasmtime generates a `ComponentType` impl
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TupleArray<T>(Box<[T]>);
|
pub struct VecInRange<T, const L: u32, const H: u32>(Vec<T>);
|
||||||
|
|
||||||
impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for TupleArray<T> {
|
impl<'a, T: Arbitrary<'a>, const L: u32, const H: u32> Arbitrary<'a> for VecInRange<T, L, H> {
|
||||||
fn arbitrary(input: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
fn arbitrary(input: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||||
Ok(Self(
|
let mut ret = Vec::new();
|
||||||
input
|
input.arbitrary_loop(Some(L), Some(H), |input| {
|
||||||
.arbitrary_iter()?
|
ret.push(input.arbitrary()?);
|
||||||
.take(MAX_TUPLE_LENGTH)
|
Ok(std::ops::ControlFlow::Continue(()))
|
||||||
.collect::<arbitrary::Result<_>>()?,
|
})?;
|
||||||
))
|
Ok(Self(ret))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for TupleArray<T> {
|
impl<T, const L: u32, const H: u32> Deref for VecInRange<T, L, H> {
|
||||||
type Target = [T];
|
type Target = [T];
|
||||||
|
|
||||||
fn deref(&self) -> &[T] {
|
fn deref(&self) -> &[T] {
|
||||||
@@ -141,13 +115,28 @@ pub enum Type {
|
|||||||
Char,
|
Char,
|
||||||
String,
|
String,
|
||||||
List(Box<Type>),
|
List(Box<Type>),
|
||||||
Record(Box<[Type]>),
|
|
||||||
Tuple(TupleArray<Type>),
|
// Give records the ability to generate a generous amount of fields but
|
||||||
Variant(NonEmptyArray<Type>),
|
// don't let the fuzzer go too wild since `wasmparser`'s validator currently
|
||||||
|
// has hard limits in the 1000-ish range on the number of fields a record
|
||||||
|
// may contain.
|
||||||
|
Record(VecInRange<Type, 0, 200>),
|
||||||
|
|
||||||
|
// Tuples can only have up to 16 type parameters in wasmtime right now for
|
||||||
|
// the static API.
|
||||||
|
Tuple(VecInRange<Type, 0, 16>),
|
||||||
|
|
||||||
|
// Like records, allow a good number of variants, but variants require at
|
||||||
|
// least one case.
|
||||||
|
Variant(VecInRange<Type, 1, 200>),
|
||||||
Enum(UsizeInRange<1, 257>),
|
Enum(UsizeInRange<1, 257>),
|
||||||
Union(NonEmptyArray<Type>),
|
Union(VecInRange<Type, 1, 200>),
|
||||||
|
|
||||||
Option(Box<Type>),
|
Option(Box<Type>),
|
||||||
Expected { ok: Box<Type>, err: Box<Type> },
|
Expected { ok: Box<Type>, err: Box<Type> },
|
||||||
|
|
||||||
|
// Generate 0 flags all the way up to 65 flags which exercises the 0 to
|
||||||
|
// 3 x u32 cases.
|
||||||
Flags(UsizeInRange<0, 65>),
|
Flags(UsizeInRange<0, 65>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user