/src/wasm-tools/crates/wit-smith/src/lib.rs
Line | Count | Source |
1 | | //! A small crate to generate arbitrary WIT documents. |
2 | | //! |
3 | | //! This crate is modeled after the `wasm-smith` crate but is used to generate |
4 | | //! WIT documents instead of WebAssembly modules. This crate is intended to |
5 | | //! generate "interesting" WIT package structures in addition to interesting |
6 | | //! type structures. |
7 | | |
8 | | use arbitrary::{Result, Unstructured}; |
9 | | use wit_parser::{Resolve, ResolveErrorKind}; |
10 | | |
11 | | mod config; |
12 | | pub use self::config::Config; |
13 | | mod generate; |
14 | | |
15 | | /// Generates an arbitrary WIT document encoded as a WebAssembly binary. |
16 | | /// |
17 | | /// The `config` guides the generation of the document and the `u` bytes are |
18 | | /// used as input to construct the document. |
19 | 3.90k | pub fn smith(config: &Config, u: &mut Unstructured<'_>) -> Result<Vec<u8>> { |
20 | 3.90k | let pkgs = generate::Generator::new(config.clone()).generate(u)?; |
21 | 3.90k | let mut resolve = Resolve::default(); |
22 | 3.90k | resolve.all_features = true; |
23 | 3.90k | let mut last = None; |
24 | 6.90k | for pkg in pkgs { |
25 | 6.90k | log::trace!("appending package {:?}", pkg.name); |
26 | 6.90k | let group = pkg.sources.parse().unwrap(); |
27 | 6.90k | let id = match resolve.push_group(group) { |
28 | 6.89k | Ok(id) => id, |
29 | 18 | Err(e) => match e.kind() { |
30 | | ResolveErrorKind::InvalidTransitiveDependency { .. } => { |
31 | 18 | return Err(arbitrary::Error::IncorrectFormat); |
32 | | } |
33 | | ResolveErrorKind::ItemShadowing { .. } |
34 | | | ResolveErrorKind::StabilityMismatch { .. } => { |
35 | 0 | log::error!("{e}"); |
36 | 0 | return Err(arbitrary::Error::IncorrectFormat); |
37 | | } |
38 | | _ => { |
39 | 0 | panic!("bad wit parse: {e:?}") |
40 | | } |
41 | | }, |
42 | | }; |
43 | 6.89k | last = Some(id); |
44 | | } |
45 | 3.88k | let pkg = last.unwrap(); |
46 | | |
47 | 3.88k | let wasm = wit_component::encode(&resolve, pkg, config.canonical_names) |
48 | 3.88k | .expect("failed to encode WIT document"); |
49 | | |
50 | 3.88k | if let Err(e) = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures::all()) |
51 | 3.88k | .validate_all(&wasm) |
52 | | { |
53 | | // Handle disallowing `stream<char>` here vs not generating it to start |
54 | | // with as it's a bit easier to handle. |
55 | 39 | if e.to_string() |
56 | 39 | .contains("`stream<char>` is not valid at this time") |
57 | | { |
58 | 23 | return Err(arbitrary::Error::IncorrectFormat); |
59 | 16 | } |
60 | | |
61 | | // Easier to handle this limit here rather than in generation right now. |
62 | 16 | if e.to_string() |
63 | 16 | .contains("value type's maximum in-memory size exceeds maximum byte size") |
64 | | { |
65 | 16 | return Err(arbitrary::Error::IncorrectFormat); |
66 | 0 | } |
67 | 3.84k | } |
68 | 3.84k | Ok(wasm) |
69 | 3.90k | } |