Skip to content

Commit

Permalink
Make wasmparser an optional dependency of wasm-smith (#1301)
Browse files Browse the repository at this point in the history
* Make wasmparser an optional dependency of wasm-smith

* Add missing import to test

* Remove usage of `KebabStr*` from wasm-smith

Not actually needed in its current iteration of component support.

* Reorganize cfgs to reduce `#[cfg]` quantities

* Test `wasmparser` feature on CI

Ensure that it continues to build and function correctly.

* Enable wasmparser feature for `wasm-tools` CLI

---------

Co-authored-by: Alex Crichton <[email protected]>
  • Loading branch information
eqrion and alexcrichton authored Nov 20, 2023
1 parent 56acc5a commit f8716d4
Show file tree
Hide file tree
Showing 9 changed files with 279 additions and 215 deletions.
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
5 changes: 3 additions & 2 deletions crates/wasm-smith/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@ 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" }

[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
libfuzzer-sys = { workspace = true }

[features]
_internal_cli = ["serde", "serde_derive"]
_internal_cli = ["serde", "serde_derive", "wasmparser"]
33 changes: 16 additions & 17 deletions crates/wasm-smith/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use std::{
rc::Rc,
};
use wasm_encoder::{ComponentTypeRef, ComponentValType, PrimitiveValType, TypeBounds, ValType};
use wasmparser::names::KebabString;

mod encode;

Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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![] }),
Expand Down Expand Up @@ -2018,7 +2017,7 @@ enum ComponentTypeDef {
Alias(Alias),
Import(Import),
Export {
name: KebabString,
name: String,
url: Option<String>,
ty: ComponentTypeRef,
},
Expand Down Expand Up @@ -2046,16 +2045,16 @@ enum InstanceTypeDecl {
Type(Rc<Type>),
Alias(Alias),
Export {
name: KebabString,
name: String,
url: Option<String>,
ty: ComponentTypeRef,
},
}

#[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 {
Expand Down Expand Up @@ -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)]
Expand All @@ -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)]
Expand All @@ -2158,7 +2157,7 @@ struct ImportSection {

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct Import {
name: KebabString,
name: String,
url: Option<String>,
ty: ComponentTypeRef,
}
Expand Down
8 changes: 4 additions & 4 deletions crates/wasm-smith/src/component/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)),
);
}
}
Expand Down
88 changes: 54 additions & 34 deletions crates/wasm-smith/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
10 changes: 4 additions & 6 deletions crates/wasm-smith/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -173,19 +172,18 @@ 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)
}

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)?;
Expand Down
Loading

0 comments on commit f8716d4

Please sign in to comment.