Repository: bytecodealliance/wasm-tools
Pull request #1301 (2023-11-20 17:37:09)

Make wasmparser an optional dependency of wasm-smith
I ran into an issue importing the latest `wast` (68.0.0) into SpiderMonkey. We vendor all rust deps into mozilla-central and there's a rule that we need to avoid vendoring duplicate dependencies with different versions if we can at all avoid it.

Today we have two explicit deps of wasm-tools, `wast` and `wasm-smith`. Those then pull in other deps like `wasm-encoder`. It looks like `wasm-smith` has a dep on `wasmparser` which then pulled in a new major version of `hashbrown`, which resulted in a duplicate with other deps of `hashbrown` in mozilla-central.

I think the easiest way for us to resolve it would be if we could avoid importing `wasmparser` for `wasm-smith`. It looks like it's very lightly used in the library (just for specifying fixed imports) and so this PR makes it optional.

I'm open to other solutions, this was just a quick thing to hack up.

Note, one issue was importing KebabStr/KebabString from wasmparser. I feel bad, but it was small enough I just made a copy inside of wasm-smith. I think having it in a shared crate would make sense, but there is not one today and so I'd need to create a new one.

eqrion: Not a problem, less work for me. Thanks!

Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index ccfcd72c..300f9ee5 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -44,6 +44,7 @@ jobs:
     - run: cargo test --locked --all
     - run: cargo test --locked -p wasmparser --benches
     - run: cargo test --locked -p wasm-encoder --all-features
+    - run: cargo test -p wasm-smith --features wasmparser
     - run: cargo build --manifest-path crates/wast/Cargo.toml --no-default-features
     - run: cargo build --manifest-path crates/wast/Cargo.toml --no-default-features --features wasm-module
     - run: cmake -S ${{github.workspace}}/examples -B ${{github.workspace}}/examples/build -DCMAKE_BUILD_TYPE=Release
diff --git a/Cargo.toml b/Cargo.toml
index f94b94be..7f3df571 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -81,7 +81,7 @@ arbitrary = { workspace = true, optional = true }
 serde = { workspace = true, optional = true }
 serde_derive = { workspace = true, optional = true }
 serde_json = { workspace = true, optional = true }
-wasm-smith = { workspace = true, features = ["_internal_cli"], optional = true }
+wasm-smith = { workspace = true, features = ["_internal_cli", "wasmparser"], optional = true }
 
 # Dependencies of `shrink`
 wasm-shrink = { workspace = true, features = ["clap"], optional = true }
diff --git a/crates/wasm-smith/Cargo.toml b/crates/wasm-smith/Cargo.toml
index 32c1ecbf..aa677983 100644
--- a/crates/wasm-smith/Cargo.toml
+++ b/crates/wasm-smith/Cargo.toml
@@ -23,11 +23,12 @@ leb128 = { workspace = true }
 serde = { workspace = true, optional = true }
 serde_derive = { workspace = true, optional = true }
 wasm-encoder = { workspace = true }
-wasmparser = { workspace = true }
+wasmparser = { workspace = true, optional = true }
 
 [dev-dependencies]
 criterion = { workspace = true }
 rand = { workspace = true }
+wasmparser = { workspace = true }
 wasmprinter = { path = "../wasmprinter" }
 wat = { path = "../wat" }
 
@@ -35,4 +36,4 @@ wat = { path = "../wat" }
 libfuzzer-sys = { workspace = true }
 
 [features]
-_internal_cli = ["serde", "serde_derive"]
+_internal_cli = ["serde", "serde_derive", "wasmparser"]
diff --git a/crates/wasm-smith/src/component.rs b/crates/wasm-smith/src/component.rs
index 440226bc..a9f8f005 100644
--- a/crates/wasm-smith/src/component.rs
+++ b/crates/wasm-smith/src/component.rs
@@ -14,7 +14,6 @@ use std::{
     rc::Rc,
 };
 use wasm_encoder::{ComponentTypeRef, ComponentValType, PrimitiveValType, TypeBounds, ValType};
-use wasmparser::names::KebabString;
 
 mod encode;
 
@@ -124,10 +123,10 @@ struct ComponentContext {
     num_imports: usize,
 
     // The set of names of imports we've generated thus far.
-    import_names: HashSet<KebabString>,
+    import_names: HashSet<String>,
 
     // The set of URLs of imports we've generated thus far.
-    import_urls: HashSet<KebabString>,
+    import_urls: HashSet<String>,
 
     // This component's function index space.
     funcs: Vec<ComponentOrCoreFuncType>,
@@ -1095,15 +1094,15 @@ impl ComponentBuilder {
     fn arbitrary_instance_type_def(
         &mut self,
         u: &mut Unstructured,
-        exports: &mut HashSet<KebabString>,
-        export_urls: &mut HashSet<KebabString>,
+        exports: &mut HashSet<String>,
+        export_urls: &mut HashSet<String>,
         type_fuel: &mut u32,
     ) -> Result<InstanceTypeDecl> {
         let mut choices: Vec<
             fn(
                 &mut ComponentBuilder,
-                &mut HashSet<KebabString>,
-                &mut HashSet<KebabString>,
+                &mut HashSet<String>,
+                &mut HashSet<String>,
                 &mut Unstructured,
                 &mut u32,
             ) -> Result<InstanceTypeDecl>,
@@ -1498,7 +1497,7 @@ impl ComponentBuilder {
         }
     }
 
-    fn push_import(&mut self, name: KebabString, url: Option<String>, ty: ComponentTypeRef) {
+    fn push_import(&mut self, name: String, url: Option<String>, ty: ComponentTypeRef) {
         let nth = match self.ensure_section(
             |sec| matches!(sec, Section::Import(_)),
             || Section::Import(ImportSection { imports: vec![] }),
@@ -2018,7 +2017,7 @@ enum ComponentTypeDef {
     Alias(Alias),
     Import(Import),
     Export {
-        name: KebabString,
+        name: String,
         url: Option<String>,
         ty: ComponentTypeRef,
     },
@@ -2046,7 +2045,7 @@ enum InstanceTypeDecl {
     Type(Rc<Type>),
     Alias(Alias),
     Export {
-        name: KebabString,
+        name: String,
         url: Option<String>,
         ty: ComponentTypeRef,
     },
@@ -2054,8 +2053,8 @@ enum InstanceTypeDecl {
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 struct FuncType {
-    params: Vec<(KebabString, ComponentValType)>,
-    results: Vec<(Option<KebabString>, ComponentValType)>,
+    params: Vec<(String, ComponentValType)>,
+    results: Vec<(Option<String>, ComponentValType)>,
 }
 
 impl FuncType {
@@ -2112,12 +2111,12 @@ enum DefinedType {
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 struct RecordType {
-    fields: Vec<(KebabString, ComponentValType)>,
+    fields: Vec<(String, ComponentValType)>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 struct VariantType {
-    cases: Vec<(KebabString, Option<ComponentValType>, Option<u32>)>,
+    cases: Vec<(String, Option<ComponentValType>, Option<u32>)>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -2132,12 +2131,12 @@ struct TupleType {
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 struct FlagsType {
-    fields: Vec<KebabString>,
+    fields: Vec<String>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 struct EnumType {
-    variants: Vec<KebabString>,
+    variants: Vec<String>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -2158,7 +2157,7 @@ struct ImportSection {
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 struct Import {
-    name: KebabString,
+    name: String,
     url: Option<String>,
     ty: ComponentTypeRef,
 }
diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs
index 3547fc07..bcb6efd2 100644
--- a/crates/wasm-smith/src/component/encode.rs
+++ b/crates/wasm-smith/src/component/encode.rs
@@ -2,7 +2,6 @@ use std::borrow::Cow;
 
 use super::*;
 use wasm_encoder::{ComponentExportKind, ComponentOuterAliasKind, ExportKind};
-use wasmparser::names::KebabStr;
 
 impl Component {
     /// Encode this Wasm component into bytes.
@@ -169,9 +168,10 @@ impl Type {
                     f.result(ty);
                 } else {
                     f.results(
-                        func_ty.results.iter().map(|(name, ty)| {
-                            (name.as_deref().map(KebabStr::as_str).unwrap(), *ty)
-                        }),
+                        func_ty
+                            .results
+                            .iter()
+                            .map(|(name, ty)| (name.as_deref().unwrap(), *ty)),
                     );
                 }
             }
diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs
index 3bd984b4..11d0e546 100644
--- a/crates/wasm-smith/src/core.rs
+++ b/crates/wasm-smith/src/core.rs
@@ -539,11 +539,29 @@ impl Module {
     /// the caller should generate arbitrary imports.
     fn arbitrary_imports_from_available(&mut self, u: &mut Unstructured) -> Result<bool> {
         let example_module = if let Some(wasm) = self.config.available_imports() {
-            wasm
+            wasm.into_owned()
         } else {
             return Ok(false);
         };
 
+        #[cfg(feature = "wasmparser")]
+        {
+            self._arbitrary_imports_from_available(u, &example_module)?;
+            Ok(true)
+        }
+        #[cfg(not(feature = "wasmparser"))]
+        {
+            let _ = (example_module, u);
+            panic!("support for `available_imports` was disabled at compile time");
+        }
+    }
+
+    #[cfg(feature = "wasmparser")]
+    fn _arbitrary_imports_from_available(
+        &mut self,
+        u: &mut Unstructured,
+        example_module: &[u8],
+    ) -> Result<()> {
         // First, parse the module-by-example to collect the types and imports.
         //
         // `available_types` will map from a signature index (which is the same as the index into
@@ -717,7 +735,41 @@ impl Module {
         self.types.extend(new_types);
         self.imports.extend(new_imports);
 
-        Ok(true)
+        return Ok(());
+
+        /// Convert a wasmparser's `ValType` to a `wasm_encoder::ValType`.
+        fn convert_type(parsed_type: wasmparser::ValType) -> ValType {
+            use wasmparser::ValType::*;
+            match parsed_type {
+                I32 => ValType::I32,
+                I64 => ValType::I64,
+                F32 => ValType::F32,
+                F64 => ValType::F64,
+                V128 => ValType::V128,
+                Ref(ty) => ValType::Ref(convert_reftype(ty)),
+            }
+        }
+
+        fn convert_reftype(ty: wasmparser::RefType) -> RefType {
+            wasm_encoder::RefType {
+                nullable: ty.is_nullable(),
+                heap_type: match ty.heap_type() {
+                    wasmparser::HeapType::Func => HeapType::Func,
+                    wasmparser::HeapType::Extern => HeapType::Extern,
+                    wasmparser::HeapType::Any => HeapType::Any,
+                    wasmparser::HeapType::None => HeapType::None,
+                    wasmparser::HeapType::NoExtern => HeapType::NoExtern,
+                    wasmparser::HeapType::NoFunc => HeapType::NoFunc,
+                    wasmparser::HeapType::Eq => HeapType::Eq,
+                    wasmparser::HeapType::Struct => HeapType::Struct,
+                    wasmparser::HeapType::Array => HeapType::Array,
+                    wasmparser::HeapType::I31 => HeapType::I31,
+                    wasmparser::HeapType::Concrete(i) => {
+                        HeapType::Concrete(i.as_module_index().unwrap())
+                    }
+                },
+            }
+        }
     }
 
     fn type_of(&self, kind: ExportKind, index: u32) -> EntityType {
@@ -1627,38 +1679,6 @@ fn arbitrary_vec_u8(u: &mut Unstructured) -> Result<Vec<u8>> {
     Ok(u.bytes(size)?.to_vec())
 }
 
-/// Convert a wasmparser's `ValType` to a `wasm_encoder::ValType`.
-fn convert_type(parsed_type: wasmparser::ValType) -> ValType {
-    use wasmparser::ValType::*;
-    match parsed_type {
-        I32 => ValType::I32,
-        I64 => ValType::I64,
-        F32 => ValType::F32,
-        F64 => ValType::F64,
-        V128 => ValType::V128,
-        Ref(ty) => ValType::Ref(convert_reftype(ty)),
-    }
-}
-
-fn convert_reftype(ty: wasmparser::RefType) -> RefType {
-    wasm_encoder::RefType {
-        nullable: ty.is_nullable(),
-        heap_type: match ty.heap_type() {
-            wasmparser::HeapType::Func => HeapType::Func,
-            wasmparser::HeapType::Extern => HeapType::Extern,
-            wasmparser::HeapType::Any => HeapType::Any,
-            wasmparser::HeapType::None => HeapType::None,
-            wasmparser::HeapType::NoExtern => HeapType::NoExtern,
-            wasmparser::HeapType::NoFunc => HeapType::NoFunc,
-            wasmparser::HeapType::Eq => HeapType::Eq,
-            wasmparser::HeapType::Struct => HeapType::Struct,
-            wasmparser::HeapType::Array => HeapType::Array,
-            wasmparser::HeapType::I31 => HeapType::I31,
-            wasmparser::HeapType::Concrete(i) => HeapType::Concrete(i.as_module_index().unwrap()),
-        },
-    }
-}
-
 impl EntityType {
     fn size(&self) -> u32 {
         match self {
diff --git a/crates/wasm-smith/src/lib.rs b/crates/wasm-smith/src/lib.rs
index 941843a3..1a8d5d56 100644
--- a/crates/wasm-smith/src/lib.rs
+++ b/crates/wasm-smith/src/lib.rs
@@ -65,7 +65,6 @@ use arbitrary::{Result, Unstructured};
 pub use component::{Component, ConfiguredComponent};
 pub use config::{Config, DefaultConfig, SwarmConfig};
 use std::{collections::HashSet, fmt::Write, str};
-use wasmparser::names::{KebabStr, KebabString};
 
 /// Do something an arbitrary number of times.
 ///
@@ -136,9 +135,9 @@ pub(crate) fn unique_string(
 
 pub(crate) fn unique_kebab_string(
     max_size: usize,
-    names: &mut HashSet<KebabString>,
+    names: &mut HashSet<String>,
     u: &mut Unstructured,
-) -> Result<KebabString> {
+) -> Result<String> {
     let size = std::cmp::min(u.arbitrary_len::<u8>()?, max_size);
     let mut name = String::with_capacity(size);
     let mut require_alpha = true;
@@ -173,11 +172,10 @@ pub(crate) fn unique_kebab_string(
         name.push('a');
     }
 
-    while names.contains(KebabStr::new(&name).unwrap()) {
+    while names.contains(&name) {
         write!(&mut name, "{}", names.len()).unwrap();
     }
 
-    let name = KebabString::new(name).unwrap();
     names.insert(name.clone());
 
     Ok(name)
@@ -185,7 +183,7 @@ pub(crate) fn unique_kebab_string(
 
 pub(crate) fn unique_url(
     max_size: usize,
-    names: &mut HashSet<KebabString>,
+    names: &mut HashSet<String>,
     u: &mut Unstructured,
 ) -> Result<String> {
     let path = unique_kebab_string(max_size, names, u)?;


Test patch:
diff --git a/crates/wasm-smith/tests/available_imports.rs b/crates/wasm-smith/tests/available_imports.rs
new file mode 100644
index 00000000..9d12a2af
--- /dev/null
+++ b/crates/wasm-smith/tests/available_imports.rs
@@ -0,0 +1,195 @@
+#![cfg(feature = "wasmparser")]
+
+use arbitrary::{Arbitrary, Unstructured};
+use rand::{rngs::SmallRng, RngCore, SeedableRng};
+use std::collections::HashMap;
+use wasm_smith::{Config, Module, SwarmConfig};
+use wasmparser::{Parser, TypeRef, ValType};
+use wasmparser::{Validator, WasmFeatures};
+
+#[test]
+fn smoke_test_imports_config() {
+    let mut n_partial = 0;
+    let mut global_imports_seen = HashMap::<_, bool>::new();
+    let mut rng = SmallRng::seed_from_u64(11);
+    let mut buf = vec![0; 512];
+    for _ in 0..1024 {
+        rng.fill_bytes(&mut buf);
+
+        let mut u = Unstructured::new(&buf);
+        let (config, available) = import_config(&mut u);
+        let features = parser_features_from_config(&config);
+
+        if let Ok(module) = Module::new(config, &mut u) {
+            let wasm_bytes = module.to_bytes();
+            let mut validator = Validator::new_with_features(features);
+            validate(&mut validator, &wasm_bytes);
+            let mut imports_seen = available
+                .iter()
+                .map(|(m, f, t)| ((*m, *f), (false, t)))
+                .collect::<HashMap<_, _>>();
+            let mut sig_types = Vec::new();
+
+            for payload in Parser::new(0).parse_all(&wasm_bytes) {
+                let payload = payload.unwrap();
+                if let wasmparser::Payload::TypeSection(rdr) = payload {
+                    // Gather the signature types to later check function types against.
+                    for ty in rdr.into_iter_err_on_gc_types() {
+                        sig_types.push(ty.unwrap());
+                    }
+                } else if let wasmparser::Payload::ImportSection(rdr) = payload {
+                    // Read out imports, checking that they all are within the list of expected
+                    // imports (i.e. we don't generate arbitrary ones), and that we handle the
+                    // logic correctly (i.e. signature types are as expected)
+                    for import in rdr {
+                        let import = import.unwrap();
+                        use AvailableImportKind as I;
+                        let entry = imports_seen.get_mut(&(import.module, import.name));
+                        match (entry, &import.ty) {
+                            (Some((true, _)), _) => panic!("duplicate import of {:?}", import),
+                            (Some((seen, I::Memory)), TypeRef::Memory(_)) => *seen = true,
+                            (Some((seen, I::Global(t))), TypeRef::Global(gt))
+                                if *t == gt.content_type =>
+                            {
+                                *seen = true
+                            }
+                            (Some((seen, I::Table(t))), TypeRef::Table(tt))
+                                if *t == ValType::Ref(tt.element_type) =>
+                            {
+                                *seen = true
+                            }
+                            (Some((seen, I::Func(p, r))), TypeRef::Func(sig_idx))
+                                if sig_types[*sig_idx as usize].params() == *p
+                                    && sig_types[*sig_idx as usize].results() == *r =>
+                            {
+                                *seen = true
+                            }
+                            (
+                                Some((seen, I::Tag(p))),
+                                TypeRef::Tag(wasmparser::TagType { func_type_idx, .. }),
+                            ) if sig_types[*func_type_idx as usize].params() == *p
+                                && sig_types[*func_type_idx as usize].results().is_empty() =>
+                            {
+                                *seen = true
+                            }
+                            (Some((_, expected)), _) => panic!(
+                                "import {:?} type mismatch, expected: {:?}",
+                                import, expected
+                            ),
+                            (None, _) => panic!("import of an unknown entity: {:?}", import),
+                        }
+                    }
+                }
+            }
+
+            // Verify that we have seen both instances with partial imports (i.e. we don't always
+            // just copy over all the imports from the example module) and also that we eventually
+            // observe all of the imports being used (i.e. selection is reasonably random)
+            for (m, f, _) in &available[..] {
+                let seen = imports_seen[&(*m, *f)];
+                let global_seen = global_imports_seen
+                    .entry((m.to_string(), f.to_string()))
+                    .or_default();
+                *global_seen |= seen.0;
+            }
+            if !imports_seen.values().all(|v| v.0) {
+                n_partial += 1;
+            }
+        }
+    }
+    assert!(global_imports_seen.values().all(|v| *v));
+    assert!(n_partial > 0);
+}
+
+#[derive(Debug)]
+enum AvailableImportKind {
+    Func(&'static [ValType], &'static [ValType]),
+    Tag(&'static [ValType]),
+    Global(ValType),
+    Table(ValType),
+    Memory,
+}
+
+fn import_config(
+    u: &mut Unstructured,
+) -> (
+    SwarmConfig,
+    Vec<(&'static str, &'static str, AvailableImportKind)>,
+) {
+    let mut config = SwarmConfig::arbitrary(u).expect("arbitrary swarm");
+    config.exceptions_enabled = u.arbitrary().expect("exceptions enabled for swarm");
+    let available = {
+        use {AvailableImportKind::*, ValType::*};
+        vec![
+            ("env", "pi", Func(&[I32], &[])),
+            ("env", "pi2", Func(&[I32], &[])),
+            ("env", "pipi2", Func(&[I32, I32], &[])),
+            ("env", "po", Func(&[], &[I32])),
+            ("env", "pipo", Func(&[I32], &[I32])),
+            ("env", "popo", Func(&[], &[I32, I32])),
+            ("env", "mem", Memory),
+            ("env", "tbl", Table(ValType::FUNCREF)),
+            ("vars", "g", Global(I64)),
+            ("tags", "tag1", Tag(&[I32])),
+        ]
+    };
+    config.available_imports = Some(
+        wat::parse_str(
+            r#"
+            (module
+                (import "env" "pi" (func (param i32)))
+                (import "env" "pi2" (func (param i32)))
+                (import "env" "pipi2" (func (param i32 i32)))
+                (import "env" "po" (func (result i32)))
+                (import "env" "pipo" (func (param i32) (result i32)))
+                (import "env" "popo" (func (result i32 i32)))
+                (import "env" "mem" (memory 1 16))
+                (import "env" "tbl" (table 1 16 funcref))
+                (import "vars" "g" (global i64))
+                (import "tags" "tag1" (tag (param i32)))
+            )
+            "#,
+        )
+        .unwrap()
+        .into(),
+    );
+    (config, available)
+}
+
+fn parser_features_from_config(config: &impl Config) -> WasmFeatures {
+    WasmFeatures {
+        mutable_global: true,
+        saturating_float_to_int: config.saturating_float_to_int_enabled(),
+        sign_extension: config.sign_extension_ops_enabled(),
+        reference_types: config.reference_types_enabled(),
+        multi_value: config.multi_value_enabled(),
+        bulk_memory: config.bulk_memory_enabled(),
+        simd: config.simd_enabled(),
+        relaxed_simd: config.relaxed_simd_enabled(),
+        multi_memory: config.max_memories() > 1,
+        exceptions: config.exceptions_enabled(),
+        memory64: config.memory64_enabled(),
+        tail_call: config.tail_call_enabled(),
+
+        threads: false,
+        floats: true,
+        extended_const: false,
+        component_model: false,
+        function_references: false,
+        memory_control: false,
+        gc: false,
+        component_model_values: false,
+    }
+}
+
+fn validate(validator: &mut Validator, bytes: &[u8]) {
+    let err = match validator.validate_all(bytes) {
+        Ok(_) => return,
+        Err(e) => e,
+    };
+    drop(std::fs::write("test.wasm", &bytes));
+    if let Ok(text) = wasmprinter::print_bytes(bytes) {
+        drop(std::fs::write("test.wat", &text));
+    }
+    panic!("wasm failed to validate {:?}", err);
+}
diff --git a/crates/wasm-smith/tests/core.rs b/crates/wasm-smith/tests/core.rs
index 4a563566..a33c50aa 100644
--- a/crates/wasm-smith/tests/core.rs
+++ b/crates/wasm-smith/tests/core.rs
@@ -1,8 +1,7 @@
 use arbitrary::{Arbitrary, Unstructured};
 use rand::{rngs::SmallRng, RngCore, SeedableRng};
-use std::collections::HashMap;
 use wasm_smith::{Config, ConfiguredModule, Module, SwarmConfig};
-use wasmparser::{Parser, TypeRef, ValType, Validator, WasmFeatures};
+use wasmparser::{Validator, WasmFeatures};
 
 #[test]
 fn smoke_test_module() {
@@ -102,100 +101,6 @@ fn smoke_can_smith_valid_webassembly_one_point_oh() {
     }
 }
 
-#[test]
-fn smoke_test_imports_config() {
-    let mut n_partial = 0;
-    let mut global_imports_seen = HashMap::<_, bool>::new();
-    let mut rng = SmallRng::seed_from_u64(11);
-    let mut buf = vec![0; 512];
-    for _ in 0..1024 {
-        rng.fill_bytes(&mut buf);
-
-        let mut u = Unstructured::new(&buf);
-        let (config, available) = import_config(&mut u);
-        let features = parser_features_from_config(&config);
-
-        if let Ok(module) = Module::new(config, &mut u) {
-            let wasm_bytes = module.to_bytes();
-            let mut validator = Validator::new_with_features(features);
-            validate(&mut validator, &wasm_bytes);
-            let mut imports_seen = available
-                .iter()
-                .map(|(m, f, t)| ((*m, *f), (false, t)))
-                .collect::<HashMap<_, _>>();
-            let mut sig_types = Vec::new();
-
-            for payload in Parser::new(0).parse_all(&wasm_bytes) {
-                let payload = payload.unwrap();
-                if let wasmparser::Payload::TypeSection(rdr) = payload {
-                    // Gather the signature types to later check function types against.
-                    for ty in rdr.into_iter_err_on_gc_types() {
-                        sig_types.push(ty.unwrap());
-                    }
-                } else if let wasmparser::Payload::ImportSection(rdr) = payload {
-                    // Read out imports, checking that they all are within the list of expected
-                    // imports (i.e. we don't generate arbitrary ones), and that we handle the
-                    // logic correctly (i.e. signature types are as expected)
-                    for import in rdr {
-                        let import = import.unwrap();
-                        use AvailableImportKind as I;
-                        let entry = imports_seen.get_mut(&(import.module, import.name));
-                        match (entry, &import.ty) {
-                            (Some((true, _)), _) => panic!("duplicate import of {:?}", import),
-                            (Some((seen, I::Memory)), TypeRef::Memory(_)) => *seen = true,
-                            (Some((seen, I::Global(t))), TypeRef::Global(gt))
-                                if *t == gt.content_type =>
-                            {
-                                *seen = true
-                            }
-                            (Some((seen, I::Table(t))), TypeRef::Table(tt))
-                                if *t == ValType::Ref(tt.element_type) =>
-                            {
-                                *seen = true
-                            }
-                            (Some((seen, I::Func(p, r))), TypeRef::Func(sig_idx))
-                                if sig_types[*sig_idx as usize].params() == *p
-                                    && sig_types[*sig_idx as usize].results() == *r =>
-                            {
-                                *seen = true
-                            }
-                            (
-                                Some((seen, I::Tag(p))),
-                                TypeRef::Tag(wasmparser::TagType { func_type_idx, .. }),
-                            ) if sig_types[*func_type_idx as usize].params() == *p
-                                && sig_types[*func_type_idx as usize].results().is_empty() =>
-                            {
-                                *seen = true
-                            }
-                            (Some((_, expected)), _) => panic!(
-                                "import {:?} type mismatch, expected: {:?}",
-                                import, expected
-                            ),
-                            (None, _) => panic!("import of an unknown entity: {:?}", import),
-                        }
-                    }
-                }
-            }
-
-            // Verify that we have seen both instances with partial imports (i.e. we don't always
-            // just copy over all the imports from the example module) and also that we eventually
-            // observe all of the imports being used (i.e. selection is reasonably random)
-            for (m, f, _) in &available[..] {
-                let seen = imports_seen[&(*m, *f)];
-                let global_seen = global_imports_seen
-                    .entry((m.to_string(), f.to_string()))
-                    .or_default();
-                *global_seen |= seen.0;
-            }
-            if !imports_seen.values().all(|v| v.0) {
-                n_partial += 1;
-            }
-        }
-    }
-    assert!(global_imports_seen.values().all(|v| *v));
-    assert!(n_partial > 0);
-}
-
 #[test]
 fn smoke_test_no_trapping_mode() {
     let mut rng = SmallRng::seed_from_u64(0);
@@ -224,61 +129,6 @@ fn wasm_features() -> WasmFeatures {
     }
 }
 
-#[derive(Debug)]
-enum AvailableImportKind {
-    Func(&'static [ValType], &'static [ValType]),
-    Tag(&'static [ValType]),
-    Global(ValType),
-    Table(ValType),
-    Memory,
-}
-
-fn import_config(
-    u: &mut Unstructured,
-) -> (
-    SwarmConfig,
-    Vec<(&'static str, &'static str, AvailableImportKind)>,
-) {
-    let mut config = SwarmConfig::arbitrary(u).expect("arbitrary swarm");
-    config.exceptions_enabled = u.arbitrary().expect("exceptions enabled for swarm");
-    let available = {
-        use {AvailableImportKind::*, ValType::*};
-        vec![
-            ("env", "pi", Func(&[I32], &[])),
-            ("env", "pi2", Func(&[I32], &[])),
-            ("env", "pipi2", Func(&[I32, I32], &[])),
-            ("env", "po", Func(&[], &[I32])),
-            ("env", "pipo", Func(&[I32], &[I32])),
-            ("env", "popo", Func(&[], &[I32, I32])),
-            ("env", "mem", Memory),
-            ("env", "tbl", Table(ValType::FUNCREF)),
-            ("vars", "g", Global(I64)),
-            ("tags", "tag1", Tag(&[I32])),
-        ]
-    };
-    config.available_imports = Some(
-        wat::parse_str(
-            r#"
-            (module
-                (import "env" "pi" (func (param i32)))
-                (import "env" "pi2" (func (param i32)))
-                (import "env" "pipi2" (func (param i32 i32)))
-                (import "env" "po" (func (result i32)))
-                (import "env" "pipo" (func (param i32) (result i32)))
-                (import "env" "popo" (func (result i32 i32)))
-                (import "env" "mem" (memory 1 16))
-                (import "env" "tbl" (table 1 16 funcref))
-                (import "vars" "g" (global i64))
-                (import "tags" "tag1" (tag (param i32)))
-            )
-            "#,
-        )
-        .unwrap()
-        .into(),
-    );
-    (config, available)
-}
-
 fn parser_features_from_config(config: &impl Config) -> WasmFeatures {
     WasmFeatures {
         mutable_global: true,