You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
5.0 KiB
158 lines
5.0 KiB
fn main() -> anyhow::Result<()> {
|
|
component::generate_static_api_tests()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
mod component {
|
|
use anyhow::{anyhow, Context, Error, Result};
|
|
use arbitrary::{Arbitrary, Unstructured};
|
|
use component_fuzz_util::{self, Declarations, TestCase};
|
|
use proc_macro2::TokenStream;
|
|
use quote::{format_ident, quote};
|
|
use rand::rngs::StdRng;
|
|
use rand::{Rng, SeedableRng};
|
|
use std::env;
|
|
use std::fmt::Write;
|
|
use std::fs;
|
|
use std::iter;
|
|
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
|
|
pub fn generate_static_api_tests() -> Result<()> {
|
|
println!("cargo:rerun-if-changed=build.rs");
|
|
let out_dir = PathBuf::from(
|
|
env::var_os("OUT_DIR").expect("The OUT_DIR environment variable must be set"),
|
|
);
|
|
|
|
let mut out = String::new();
|
|
write_static_api_tests(&mut out)?;
|
|
|
|
let output = out_dir.join("static_component_api.rs");
|
|
fs::write(&output, out)?;
|
|
|
|
drop(Command::new("rustfmt").arg(&output).status());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn write_static_api_tests(out: &mut String) -> Result<()> {
|
|
let seed = if let Ok(seed) = env::var("WASMTIME_FUZZ_SEED") {
|
|
seed.parse::<u64>()
|
|
.with_context(|| anyhow!("expected u64 in WASMTIME_FUZZ_SEED"))?
|
|
} else {
|
|
StdRng::from_entropy().gen()
|
|
};
|
|
|
|
eprintln!(
|
|
"using seed {seed} (set WASMTIME_FUZZ_SEED={seed} in your environment to reproduce)"
|
|
);
|
|
|
|
let mut rng = StdRng::seed_from_u64(seed);
|
|
|
|
const TEST_CASE_COUNT: usize = 100;
|
|
|
|
let mut tests = TokenStream::new();
|
|
|
|
let name_counter = &mut 0;
|
|
|
|
let mut declarations = TokenStream::new();
|
|
|
|
for index in 0..TEST_CASE_COUNT {
|
|
let mut bytes = Vec::new();
|
|
|
|
let case = loop {
|
|
let count = rng.gen_range(1000..2000);
|
|
bytes.extend(iter::repeat_with(|| rng.gen::<u8>()).take(count));
|
|
|
|
match TestCase::arbitrary(&mut Unstructured::new(&bytes)) {
|
|
Ok(case) => break case,
|
|
Err(arbitrary::Error::NotEnoughData) => (),
|
|
Err(error) => return Err(Error::from(error)),
|
|
}
|
|
};
|
|
|
|
let Declarations {
|
|
types,
|
|
params,
|
|
results,
|
|
import_and_export,
|
|
encoding1,
|
|
encoding2,
|
|
} = case.declarations();
|
|
|
|
let test = format_ident!("static_api_test{}", case.params.len());
|
|
|
|
let rust_params = case
|
|
.params
|
|
.iter()
|
|
.map(|ty| {
|
|
let ty = component_fuzz_util::rust_type(&ty, name_counter, &mut declarations);
|
|
quote!(#ty,)
|
|
})
|
|
.collect::<TokenStream>();
|
|
|
|
let rust_results = case
|
|
.results
|
|
.iter()
|
|
.map(|ty| {
|
|
let ty = component_fuzz_util::rust_type(&ty, name_counter, &mut declarations);
|
|
quote!(#ty,)
|
|
})
|
|
.collect::<TokenStream>();
|
|
|
|
let test = quote!(#index => component_types::#test::<#rust_params (#rust_results)>(
|
|
input,
|
|
{
|
|
static DECLS: Declarations = Declarations {
|
|
types: Cow::Borrowed(#types),
|
|
params: Cow::Borrowed(#params),
|
|
results: Cow::Borrowed(#results),
|
|
import_and_export: Cow::Borrowed(#import_and_export),
|
|
encoding1: #encoding1,
|
|
encoding2: #encoding2,
|
|
};
|
|
&DECLS
|
|
}
|
|
),);
|
|
|
|
tests.extend(test);
|
|
}
|
|
|
|
let module = quote! {
|
|
#[allow(unused_imports)]
|
|
fn static_component_api_target(input: &mut libfuzzer_sys::arbitrary::Unstructured) -> libfuzzer_sys::arbitrary::Result<()> {
|
|
use anyhow::Result;
|
|
use component_fuzz_util::Declarations;
|
|
use component_test_util::{self, Float32, Float64};
|
|
use libfuzzer_sys::arbitrary::{self, Arbitrary};
|
|
use std::borrow::Cow;
|
|
use std::sync::{Arc, Once};
|
|
use wasmtime::component::{ComponentType, Lift, Lower};
|
|
use wasmtime_fuzzing::generators::component_types;
|
|
|
|
const SEED: u64 = #seed;
|
|
|
|
static ONCE: Once = Once::new();
|
|
|
|
ONCE.call_once(|| {
|
|
eprintln!(
|
|
"Seed {SEED} was used to generate static component API fuzz tests.\n\
|
|
Set WASMTIME_FUZZ_SEED={SEED} in your environment at build time to reproduce."
|
|
);
|
|
});
|
|
|
|
#declarations
|
|
|
|
match input.int_in_range(0..=(#TEST_CASE_COUNT-1))? {
|
|
#tests
|
|
_ => unreachable!()
|
|
}
|
|
}
|
|
};
|
|
|
|
write!(out, "{module}")?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|