From 597eb6f4ce69cce196704fcc20cfc4d0768568e8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 10 Aug 2022 15:49:51 -0500 Subject: [PATCH] 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` which allow expressing all of these various requirements in one type. * Fix a compile error on `main` * Review comments --- crates/misc/component-fuzz-util/src/lib.rs | 67 +++++++++------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/crates/misc/component-fuzz-util/src/lib.rs b/crates/misc/component-fuzz-util/src/lib.rs index 2d5b75fd9254..da4e2de788bf 100644 --- a/crates/misc/component-fuzz-util/src/lib.rs +++ b/crates/misc/component-fuzz-util/src/lib.rs @@ -25,10 +25,6 @@ pub const IMPORT_FUNCTION: &str = "echo"; /// The name of the exported guest function which the host should call 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)] enum CoreType { I32, @@ -76,45 +72,23 @@ impl<'a, const L: usize, const H: usize> Arbitrary<'a> for UsizeInRange { } } -/// Wraps a `Box<[T]>` and provides an `Arbitrary` implementation that always generates non-empty slices -#[derive(Debug)] -pub struct NonEmptyArray(Box<[T]>); - -impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for NonEmptyArray { - fn arbitrary(input: &mut Unstructured<'a>) -> arbitrary::Result { - Ok(Self( - iter::once(input.arbitrary()) - .chain(input.arbitrary_iter()?) - .collect::>()?, - )) - } -} - -impl Deref for NonEmptyArray { - 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 /// or equal to the longest tuple for which Wasmtime generates a `ComponentType` impl #[derive(Debug)] -pub struct TupleArray(Box<[T]>); +pub struct VecInRange(Vec); -impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for TupleArray { +impl<'a, T: Arbitrary<'a>, const L: u32, const H: u32> Arbitrary<'a> for VecInRange { fn arbitrary(input: &mut Unstructured<'a>) -> arbitrary::Result { - Ok(Self( - input - .arbitrary_iter()? - .take(MAX_TUPLE_LENGTH) - .collect::>()?, - )) + let mut ret = Vec::new(); + input.arbitrary_loop(Some(L), Some(H), |input| { + ret.push(input.arbitrary()?); + Ok(std::ops::ControlFlow::Continue(())) + })?; + Ok(Self(ret)) } } -impl Deref for TupleArray { +impl Deref for VecInRange { type Target = [T]; fn deref(&self) -> &[T] { @@ -141,13 +115,28 @@ pub enum Type { Char, String, List(Box), - Record(Box<[Type]>), - Tuple(TupleArray), - Variant(NonEmptyArray), + + // Give records the ability to generate a generous amount of fields but + // 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), + + // Tuples can only have up to 16 type parameters in wasmtime right now for + // the static API. + Tuple(VecInRange), + + // Like records, allow a good number of variants, but variants require at + // least one case. + Variant(VecInRange), Enum(UsizeInRange<1, 257>), - Union(NonEmptyArray), + Union(VecInRange), + Option(Box), Expected { ok: Box, err: Box }, + + // Generate 0 flags all the way up to 65 flags which exercises the 0 to + // 3 x u32 cases. Flags(UsizeInRange<0, 65>), }