summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wasm-smith/tests
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wasm-smith/tests')
-rw-r--r--third_party/rust/wasm-smith/tests/available_imports.rs202
-rw-r--r--third_party/rust/wasm-smith/tests/component.rs43
-rw-r--r--third_party/rust/wasm-smith/tests/core.rs191
3 files changed, 436 insertions, 0 deletions
diff --git a/third_party/rust/wasm-smith/tests/available_imports.rs b/third_party/rust/wasm-smith/tests/available_imports.rs
new file mode 100644
index 0000000000..2ccc4c1cea
--- /dev/null
+++ b/third_party/rust/wasm-smith/tests/available_imports.rs
@@ -0,0 +1,202 @@
+#![cfg(feature = "wasmparser")]
+
+use arbitrary::{Arbitrary, Unstructured};
+use rand::{rngs::SmallRng, RngCore, SeedableRng};
+use std::collections::HashMap;
+use wasm_smith::{Config, Module};
+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,
+) -> (
+ Config,
+ Vec<(&'static str, &'static str, AvailableImportKind)>,
+) {
+ let mut config = Config::arbitrary(u).expect("arbitrary swarm");
+ config.gc_enabled = false;
+ 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: &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,
+ function_references: config.gc_enabled,
+ gc: config.gc_enabled,
+
+ threads: false,
+ floats: true,
+ extended_const: false,
+ component_model: false,
+ memory_control: false,
+ component_model_values: false,
+ component_model_nested_names: false,
+ }
+}
+
+fn validate(validator: &mut Validator, bytes: &[u8]) {
+ let err = match validator.validate_all(bytes) {
+ Ok(_) => return,
+ Err(e) => e,
+ };
+ eprintln!("Writing Wasm to `test.wasm`");
+ drop(std::fs::write("test.wasm", &bytes));
+ if let Ok(text) = wasmprinter::print_bytes(bytes) {
+ eprintln!("Writing WAT to `test.wat`");
+ drop(std::fs::write("test.wat", &text));
+ }
+ panic!("wasm failed to validate: {}", err);
+}
diff --git a/third_party/rust/wasm-smith/tests/component.rs b/third_party/rust/wasm-smith/tests/component.rs
new file mode 100644
index 0000000000..7d5a40159c
--- /dev/null
+++ b/third_party/rust/wasm-smith/tests/component.rs
@@ -0,0 +1,43 @@
+use arbitrary::{Arbitrary, Unstructured};
+use rand::{rngs::SmallRng, RngCore, SeedableRng};
+use wasm_smith::Component;
+
+#[test]
+#[ignore] // FIXME(#1000): need to update wasm-smith's support for components
+fn smoke_test_component() {
+ const NUM_RUNS: usize = 4096;
+
+ let mut rng = SmallRng::seed_from_u64(0);
+ let mut buf = vec![0; 1024];
+ let mut ok_count = 0;
+
+ for _ in 0..NUM_RUNS {
+ rng.fill_bytes(&mut buf);
+ let u = Unstructured::new(&buf);
+ if let Ok(component) = Component::arbitrary_take_rest(u) {
+ ok_count += 1;
+ let component = component.to_bytes();
+
+ let mut validator =
+ wasmparser::Validator::new_with_features(wasmparser::WasmFeatures {
+ component_model: true,
+ ..Default::default()
+ });
+ if let Err(e) = validator.validate_all(&component) {
+ std::fs::write("component.wasm", &component).unwrap();
+ panic!(
+ "generated component should be valid; failing binary written \
+ to `component.wasm`. Error: {}",
+ e
+ );
+ }
+ }
+ }
+
+ println!(
+ "Generated {} / {} ({:.02}%) arbitrary components okay",
+ ok_count,
+ NUM_RUNS,
+ ok_count as f64 / NUM_RUNS as f64 * 100.0
+ );
+}
diff --git a/third_party/rust/wasm-smith/tests/core.rs b/third_party/rust/wasm-smith/tests/core.rs
new file mode 100644
index 0000000000..5816f8e38b
--- /dev/null
+++ b/third_party/rust/wasm-smith/tests/core.rs
@@ -0,0 +1,191 @@
+use arbitrary::{Arbitrary, Unstructured};
+use rand::{rngs::SmallRng, RngCore, SeedableRng};
+use wasm_smith::{Config, Module};
+use wasmparser::{Validator, WasmFeatures};
+
+#[test]
+fn smoke_test_module() {
+ let mut rng = SmallRng::seed_from_u64(0);
+ let mut buf = vec![0; 2048];
+ for _ in 0..1024 {
+ rng.fill_bytes(&mut buf);
+ let u = Unstructured::new(&buf);
+ if let Ok(module) = Module::arbitrary_take_rest(u) {
+ let wasm_bytes = module.to_bytes();
+
+ let mut validator = Validator::new_with_features(wasm_features());
+ validate(&mut validator, &wasm_bytes);
+ }
+ }
+}
+
+#[test]
+fn smoke_test_ensure_termination() {
+ let mut rng = SmallRng::seed_from_u64(0);
+ let mut buf = vec![0; 2048];
+ for _ in 0..1024 {
+ rng.fill_bytes(&mut buf);
+ let u = Unstructured::new(&buf);
+ if let Ok(mut module) = Module::arbitrary_take_rest(u) {
+ module.ensure_termination(10);
+ let wasm_bytes = module.to_bytes();
+
+ let mut validator = Validator::new_with_features(wasm_features());
+ validate(&mut validator, &wasm_bytes);
+ }
+ }
+}
+
+#[test]
+fn smoke_test_swarm_config() {
+ let mut rng = SmallRng::seed_from_u64(0);
+ let mut buf = vec![0; 2048];
+ for _ in 0..1024 {
+ rng.fill_bytes(&mut buf);
+ let mut u = Unstructured::new(&buf);
+ if let Ok(config) = Config::arbitrary(&mut u) {
+ if let Ok(module) = Module::new(config, &mut u) {
+ let wasm_bytes = module.to_bytes();
+
+ let mut validator = Validator::new_with_features(wasm_features());
+ validate(&mut validator, &wasm_bytes);
+ }
+ }
+ }
+}
+
+#[test]
+fn multi_value_disabled() {
+ let mut rng = SmallRng::seed_from_u64(42);
+ let mut buf = vec![0; 2048];
+ for _ in 0..10 {
+ rng.fill_bytes(&mut buf);
+ let mut u = Unstructured::new(&buf);
+ let mut cfg = Config::arbitrary(&mut u).unwrap();
+ cfg.multi_value_enabled = false;
+ if let Ok(module) = Module::new(cfg, &mut u) {
+ let wasm_bytes = module.to_bytes();
+ let mut features = wasm_features();
+ features.multi_value = false;
+ let mut validator = Validator::new_with_features(features);
+ validate(&mut validator, &wasm_bytes);
+ }
+ }
+}
+
+#[test]
+fn smoke_can_smith_valid_webassembly_one_point_oh() {
+ let mut rng = SmallRng::seed_from_u64(42);
+ let mut buf = vec![0; 10240];
+ for _ in 0..100 {
+ rng.fill_bytes(&mut buf);
+ let mut u = Unstructured::new(&buf);
+ let mut cfg = Config::arbitrary(&mut u).unwrap();
+ cfg.sign_extension_ops_enabled = false;
+ cfg.saturating_float_to_int_enabled = false;
+ cfg.reference_types_enabled = false;
+ cfg.multi_value_enabled = false;
+ cfg.bulk_memory_enabled = false;
+ cfg.simd_enabled = false;
+ cfg.relaxed_simd_enabled = false;
+ cfg.exceptions_enabled = false;
+ cfg.memory64_enabled = false;
+ cfg.max_memories = 1;
+ cfg.max_tables = 1;
+ let features = parser_features_from_config(&cfg);
+ if let Ok(module) = Module::new(cfg, &mut u) {
+ let wasm_bytes = module.to_bytes();
+ // This table should set to `true` only features specified in wasm-core-1 spec.
+ let mut validator = Validator::new_with_features(features);
+ validate(&mut validator, &wasm_bytes);
+ }
+ }
+}
+
+#[test]
+fn smoke_test_no_trapping_mode() {
+ let mut rng = SmallRng::seed_from_u64(0);
+ let mut buf = vec![0; 2048];
+ for _ in 0..1024 {
+ rng.fill_bytes(&mut buf);
+ let mut u = Unstructured::new(&buf);
+ let mut cfg = Config::arbitrary(&mut u).unwrap();
+ cfg.disallow_traps = true;
+ if let Ok(module) = Module::new(cfg, &mut u) {
+ let wasm_bytes = module.to_bytes();
+ let mut validator = Validator::new_with_features(wasm_features());
+ validate(&mut validator, &wasm_bytes);
+ }
+ }
+}
+
+#[test]
+fn smoke_test_wasm_gc() {
+ let mut rng = SmallRng::seed_from_u64(0);
+ let mut buf = vec![0; 2048];
+ for _ in 0..1024 {
+ rng.fill_bytes(&mut buf);
+ let mut u = Unstructured::new(&buf);
+ let config = Config {
+ gc_enabled: true,
+ ..Config::default()
+ };
+ if let Ok(module) = Module::new(config, &mut u) {
+ let wasm_bytes = module.to_bytes();
+ let mut validator = Validator::new_with_features(wasm_features());
+ validate(&mut validator, &wasm_bytes);
+ }
+ }
+}
+
+fn wasm_features() -> WasmFeatures {
+ WasmFeatures {
+ multi_memory: true,
+ relaxed_simd: true,
+ memory64: true,
+ exceptions: true,
+ tail_call: true,
+ function_references: true,
+ gc: true,
+ ..WasmFeatures::default()
+ }
+}
+
+fn parser_features_from_config(config: &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,
+ component_model_nested_names: 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);
+}