├── .github └── FUNDING.yml ├── .gitignore ├── Cargo.toml ├── README.md ├── src ├── check.rs ├── count.rs ├── dudect.rs ├── errors.rs ├── fuzz.rs ├── lib.rs ├── main.rs ├── optimizer.rs ├── util.rs └── wasm.rs └── vendor └── wasmi ├── .editorconfig ├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches ├── .gitignore ├── Cargo.toml ├── build.rs ├── src │ ├── lib.rs │ ├── revcomp-input.txt │ └── revcomp-output.txt └── wasm-kernel │ ├── .gitignore │ ├── Cargo.toml │ └── src │ ├── lib.rs │ ├── regex_redux.rs │ └── rev_complement.rs ├── check.sh ├── doc.sh ├── examples ├── interpret.rs ├── invoke.rs └── tictactoe.rs ├── fuzz ├── .gitignore ├── Cargo.toml └── fuzz_targets │ ├── load.rs │ ├── load_spec.rs │ ├── load_wabt.rs │ └── load_wasmparser.rs ├── hfuzz ├── .gitignore ├── Cargo.toml ├── src │ └── main.rs └── test.sh ├── res └── fixtures │ ├── accumulate_u8.wast │ └── inc_i32.wast ├── src ├── bin │ └── instantiate.rs ├── func.rs ├── global.rs ├── host.rs ├── imports.rs ├── isa.rs ├── lib.rs ├── memory.rs ├── module.rs ├── nan_preserving_float.rs ├── prepare │ ├── compile.rs │ ├── mod.rs │ └── tests.rs ├── runner.rs ├── table.rs ├── tests │ ├── host.rs │ ├── mod.rs │ └── wasm.rs ├── types.rs └── value.rs ├── test.sh ├── tests ├── spec │ ├── mod.rs │ └── run.rs └── spec_shim.rs └── validation ├── Cargo.toml └── src ├── context.rs ├── func.rs ├── lib.rs ├── stack.rs ├── tests.rs └── util.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: phayes 4 | custom: flattr.com/@phayes 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sidefuzz" 3 | version = "0.1.2" 4 | authors = ["phayes "] 5 | edition = "2018" 6 | readme = "README.md" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/phayes/sidefuzz" 9 | description = "Fuzzer to automatically find side-channel (timing) vulnerabilities" 10 | keywords = ["fuzzing", "constant-time", "cryptography", "wasm"] 11 | categories = ["cryptography", "development-tools::testing"] 12 | 13 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 14 | rand = "0.7.3" 15 | hex = "0.4.2" 16 | statrs = "0.13.0" 17 | rolling-stats = "0.3.0" 18 | clap = "2.33.0" 19 | failure = "0.1.5" 20 | color-backtrace = { version = "0.4.2" } 21 | float_duration = { git = "https://github.com/phayes/rust-float-duration" } 22 | wasmi = { path = "./vendor/wasmi" } 23 | 24 | [dependencies] 25 | lazy_static = "1.4.0" 26 | 27 | [[bin]] 28 | name = "sidefuzz" 29 | doc = false 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## SideFuzz: Fuzzing for side-channel vulnerabilities 2 | 3 | [![docs](https://docs.rs/sidefuzz/badge.svg)](https://docs.rs/sidefuzz) 4 | [![crates.io](https://meritbadge.herokuapp.com/sidefuzz)](https://crates.io/crates/sidefuzz) 5 | [![docs](https://docs.rs/sidefuzz/badge.svg)](https://docs.rs/sidefuzz) 6 | [![patreon](https://img.shields.io/badge/patreon-donate-green.svg)](https://patreon.com/phayes) 7 | [![flattr](https://img.shields.io/badge/flattr-donate-green.svg)](https://flattr.com/@phayes) 8 | 9 | 10 | 11 | SideFuzz is an adaptive fuzzer that uses a genetic-algorithm optimizer in combination with t-statistics to find side-channel (timing) vulnerabilities in cryptography compiled to [wasm](https://webassembly.org). 12 | 13 | Fuzzing Targets can be found here: https://github.com/phayes/sidefuzz-targets 14 | 15 | ### How it works 16 | 17 | SideFuzz works by counting instructions executed in the [wasmi](https://github.com/paritytech/wasmi) wasm interpreter. It works in two phases: 18 | 19 | **Phase 1.** Uses a genetic-algorithm optimizer that tries to maximize the difference in instructions executed between two different inputs. It will continue optimizing until subsequent generations of input-pairs no longer produce any meaningful differences in the number of instructions executed. This means that it will optimize until it finds finds a local optimum in the fitness of input pairs. 20 | 21 | **Phase 2.** Once a local optimum is found, the leading input-pairs are sampled until either: 22 | 23 | - A large t-statistic (p = 0.001) is found, indicating that there is a statistically significant difference in running-time between the two inputs. This is indicative of a timing side-channel vulnerability; or 24 | 25 | - The t-statistic stays low, even after significant sampling. In this case the candidate input pairs are rejected and SideFuzz returns to phase 1, resuming the genetic-algorithm optimizer to find another local optimum. 26 | 27 | ### What it gets you 28 | 29 | Fuzzing with SideFuzz shows that your Rust code can be constant-time, but doesn't show that it _is_ constant-time on all architectures. This is because LLVM backends [can and will](http://www.reparaz.net/oscar/misc/cmov.html) ruin constant-time Rust / LLVM-IR when compiling to machine-code. SideFuzz should be considered a "good first step" to be followed up with [dudect-bencher](https://crates.io/crates/dudect-bencher) and [ctgrind](https://github.com/RustCrypto/utils/tree/master/ctgrind). It should also be noted that proper compiler support for constant-time code-generation is an unsolved problem in the Rust ecosystem. There have been some ideas around using [cranelift](https://github.com/CraneStation/cranelift) for constant-time code generation, but things are still in the brainstorming phase. 30 | 31 | ## Installation 32 | 33 | ``` 34 | rustup target add wasm32-unknown-unknown 35 | git clone git@github.com:phayes/sidefuzz.git 36 | cd sidefuzz && cargo install --path . 37 | ``` 38 | 39 | (Cannot currently do `cargo install sidefuzz` because of [this issue](https://github.com/phayes/sidefuzz/issues/12)) 40 | 41 | ## Creating a Rust fuzz target 42 | 43 | Creating a target in rust is very easy. 44 | 45 | ```rust 46 | // lib.rs 47 | #[no_mangle] 48 | pub extern "C" fn fuzz() { 49 | let input = sidefuzz::fetch_input(32); // 32 bytes of of fuzzing input as a &[u8] 50 | sidefuzz::black_box(my_hopefully_constant_fn(input)); 51 | } 52 | ``` 53 | 54 | ```toml 55 | # Cargo.toml 56 | [lib] 57 | crate-type = ["cdylib"] 58 | 59 | [dependencies] 60 | sidefuzz = "0.1.1" 61 | ``` 62 | 63 | Compile and fuzz the target like so: 64 | 65 | ```bash 66 | cargo build --release --target wasm32-unknown-unknown # Always build in release mode 67 | sidefuzz fuzz ./target/wasm32-unknown-unknown/release/my_target.wasm # Fuzzing! 68 | ``` 69 | 70 | Results can be checked like so: 71 | 72 | ```bash 73 | sidefuzz check my_target.wasm 01250bf9 ff81f7b3 74 | ``` 75 | 76 | When fixing variable-time code, sidefuzz can also help with `sidefuzz count` to quickly count the number of instructions executed by the target. 77 | 78 | ```bash 79 | sidefuzz count my_target.wasm 01250bf9 80 | ``` 81 | 82 | ## Creating a fuzz target in other languages 83 | 84 | SideFuzz works with Go, C, C++ and other langauges that compile to wasm. 85 | 86 | The wasm module should provide four exports: 87 | 88 | 1. Memory exported to "memory" 89 | 90 | 2. A function named "fuzz". This function will be repeatedly called during the fuzzing process. 91 | 92 | 3. A function named "input_pointer" that returns an i32 pointer to a location in linear memory where we can can write an array of input bytes. The "fuzz" function should read this array of bytes as input for it's fuzzing. 93 | 94 | 4. A function named "input_len" that returns an i32 with the desired length of input in bytes. 95 | 96 | ## FAQ 97 | 98 | #### 1. Why wasm? 99 | 100 | Web Assembly allows us to precisely track the number of instructions executed, the type of instructions executed, and the amount of memory used. This is much more precise than other methods such as tracking wall-time or counting CPU cycles. 101 | 102 | #### 2. Why do I always need to build in release mode? 103 | 104 | Many constant-time functions include calls to variable-time `debug_assert!()` functions that get removed during a release build. Rust's and LLVM optimizer may also mangle supposedly constant-time code in the name of optimization, introducing subtle timing vulnerabilities. Running in release mode let's us surface these issues. 105 | 106 | #### 3. I need an RNG (Random Number Generator). What do? 107 | 108 | You should make use of a PRNG with a static seed. While this is a bad idea for production code, it's great for fuzzing. See the [rsa_encrypt_pkcs1v15_message target](https://github.com/phayes/sidefuzz-targets/blob/master/rsa_encrypt_pkcs1v15_message/src/lib.rs) for an example on how to do this. 109 | 110 | #### 4. What's up with `black_box` ? 111 | 112 | `sidefuzz::black_box` is used to avoid dead-code elimination. Because we are interested in exercising the fuzzed code instead of getting results from it, the exported `fuzz` function doesn't return anything. The Rust optimizer sees all functions that don't return as dead-code and will try to eliminate them as part of it's optimizations. `black_box` is a function that is opaque to the optimizer, allowing us to exercise functions that don't return without them being optimized away. It should be used whenever calling a function that doesn't return anything or where we are ignoring the output returned. 113 | 114 | #### 5. The fuzzer gave me invalid inputs, what now? 115 | 116 | You should panic (causing a wasm trap). This will signal to the fuzzer that the inputs are invalid. 117 | 118 | #### 6. I need to do some variable-time set-up. How do I do that? 119 | 120 | You should use [`lazy_static`](https://crates.io/crates/lazy_static) to do any set-up work (like generating keys etc). The target is always run once to prime lazy statics before the real fuzzing starts. 121 | 122 | ## Related Tools 123 | 124 | 1. `dudect-bencher`. An implementation of the DudeCT constant-time function tester. In comparison to SideFuzz, this tool more closely adheres to the original dudect design. https://crates.io/crates/dudect-bencher 125 | 126 | 2. `ctgrind`. Tool for checking that functions are constant time using Valgrind. https://github.com/RustCrypto/utils/tree/master/ctgrind 127 | 128 | ## Further Reading 129 | 130 | 1. "DifFuzz: Differential Fuzzing for Side-Channel Analysis", Nilizadeh, Noller, Păsăreanu. 131 | https://arxiv.org/abs/1811.07005 132 | 133 | 2. "Dude, is my code constant time?", Reparaz et al. https://eprint.iacr.org/2016/1123.pdf 134 | 135 | 3. "Rust, dudect and constant-time crypto in debug mode", brycx. 136 | https://brycx.github.io/2019/04/21/rust-dudect-constant-time-crypto.html 137 | 138 | ## Contributors 139 | 140 | 1. Patrick Hayes ([linkedin](https://www.linkedin.com/in/patrickdhayes/)) ([github](https://github.com/phayes)) - Available for hire. 141 | -------------------------------------------------------------------------------- /src/check.rs: -------------------------------------------------------------------------------- 1 | // This file contains the "check" subcommand 2 | 3 | use crate::dudect::{DudeCT, DudeResult}; 4 | use crate::errors::SideFuzzError; 5 | use crate::util::*; 6 | use crate::wasm::WasmModule; 7 | 8 | pub struct Check { 9 | module: WasmModule, 10 | input: InputPair, 11 | } 12 | 13 | impl Check { 14 | // Create a new check command with the given wasm module and two inputs 15 | pub fn new(module: WasmModule, first: Vec, second: Vec) -> Result { 16 | if first.len() != second.len() { 17 | return Err(SideFuzzError::InputsDifferentSizes); 18 | } 19 | 20 | if first.len() != module.fuzz_len() { 21 | return Err(SideFuzzError::InputsWrongSize(module.fuzz_len())); 22 | } 23 | 24 | let input_is_str = &module.input_is_str(); 25 | 26 | Ok(Check { 27 | module: module, 28 | input: InputPair { 29 | first, 30 | second, 31 | is_str: *input_is_str, 32 | }, 33 | }) 34 | } 35 | 36 | pub fn from_file( 37 | filename: &str, 38 | first: Vec, 39 | second: Vec, 40 | ) -> Result { 41 | let module = WasmModule::from_file(filename)?; 42 | Self::new(module, first, second) 43 | } 44 | 45 | pub fn run(&mut self) -> Result<(), SideFuzzError> { 46 | // Get the instruction counts 47 | let input_is_str = self.module.input_is_str(); 48 | let scored_input = ScoredInputPair::generate( 49 | &mut self.module, 50 | self.input.first.to_vec(), 51 | self.input.second.to_vec(), 52 | input_is_str, 53 | ); 54 | 55 | // Construct DudeCT 56 | // Return success on t = 4.5 (very high confidence) 57 | // Give up on t < 0.674 (50% confidence) when over 1 million samples. 58 | let mut dudect = DudeCT::new( 59 | 4.5, // Success t-value 60 | 0.674, // Give up t-value 61 | 100_000, // Give up min samples 62 | &self.input.first, 63 | &self.input.second, 64 | self.module.clone(), 65 | )?; 66 | 67 | loop { 68 | let (t, result) = dudect.sample(10_000)?; 69 | let p = p_value_from_t_value(t); 70 | 71 | println!( 72 | "samples: {}, t-value: {}, confidence: {}%", 73 | dudect.len(), 74 | t, 75 | (1.0 - p) * 100.0 76 | ); 77 | 78 | match result { 79 | DudeResult::Ok => { 80 | println!( 81 | "Found timing difference of {} instructions between these two inputs with {}% confidence:\ninput 1: {} ({} instructions) \ninput 2: {} ({} instructions)", 82 | scored_input.score, 83 | (1.0 - p) * 100.0, 84 | hex::encode(&scored_input.pair.first), 85 | scored_input.highest, 86 | hex::encode(&scored_input.pair.second), 87 | scored_input.lowest, 88 | ); 89 | std::process::exit(0); 90 | } 91 | DudeResult::Err => { 92 | println!( 93 | "Candidate input pair rejected: t-statistic small after many samples. Target is probably constant time." 94 | ); 95 | std::process::exit(0); 96 | } 97 | DudeResult::Progress => { 98 | continue; 99 | } 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/count.rs: -------------------------------------------------------------------------------- 1 | // This file contains the "count" subcommand 2 | 3 | use crate::errors::SideFuzzError; 4 | use crate::wasm::WasmModule; 5 | 6 | pub struct Count { 7 | module: WasmModule, 8 | input: Vec, 9 | } 10 | 11 | impl Count { 12 | 13 | // Create a new check command with the given wasm module and two inputs 14 | pub fn new(module: WasmModule, input: Vec) -> Result { 15 | if input.len() != module.fuzz_len() { 16 | return Err(SideFuzzError::InputsWrongSize(module.fuzz_len())); 17 | } 18 | 19 | Ok(Count { 20 | module: module, 21 | input: input, 22 | }) 23 | } 24 | 25 | pub fn from_file(filename: &str, input: Vec) -> Result { 26 | let module = WasmModule::from_file(filename)?; 27 | Self::new(module, input) 28 | } 29 | 30 | pub fn run(&mut self) { 31 | let num_instructions = self.module.count_instructions(&self.input); 32 | match num_instructions { 33 | Ok(num) => { 34 | println!("{}", num); 35 | std::process::exit(0); 36 | } 37 | Err(e) => { 38 | println!("{}", e); 39 | std::process::exit(1); 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/dudect.rs: -------------------------------------------------------------------------------- 1 | // Contains an implementation of dudect 2 | 3 | use crate::errors::SideFuzzError; 4 | use crate::wasm::WasmModule; 5 | use rolling_stats::Stats; 6 | 7 | #[derive(Eq, PartialEq, Debug)] 8 | pub enum DudeResult { 9 | Ok, // Success 10 | Err, // Failure 11 | Progress, // Neither success nor failure, still in progress. 12 | } 13 | 14 | pub struct DudeCT<'a> { 15 | t_threshold: f64, 16 | t_fail: f64, 17 | fail_min_samples: usize, 18 | first: &'a [u8], 19 | second: &'a [u8], 20 | module: WasmModule, 21 | first_stats: Stats, 22 | second_stats: Stats, 23 | first_stats_count: usize, 24 | second_stats_count: usize, 25 | } 26 | 27 | impl<'a> DudeCT<'a> { 28 | pub fn new( 29 | t_threshold: f64, 30 | t_fail: f64, 31 | fail_min_samples: usize, 32 | first: &'a [u8], 33 | second: &'a [u8], 34 | module: WasmModule, 35 | ) -> Result { 36 | if module.fuzz_len() != first.len() || module.fuzz_len() != second.len() { 37 | return Err(SideFuzzError::InputsDifferentSizes); 38 | } 39 | 40 | Ok(DudeCT { 41 | t_threshold, 42 | t_fail, 43 | fail_min_samples, 44 | first, 45 | second, 46 | module, 47 | first_stats: Stats::new(), 48 | second_stats: Stats::new(), 49 | first_stats_count: 0, 50 | second_stats_count: 0, 51 | }) 52 | } 53 | 54 | pub fn len(&self) -> usize { 55 | self.first_stats_count + self.second_stats_count 56 | } 57 | 58 | pub fn sample(&mut self, num_samples: u64) -> Result<(f64, DudeResult), SideFuzzError> { 59 | for _ in 0..num_samples { 60 | let first_instructions = self.module.count_instructions(self.first)?; 61 | let second_instructions = self.module.count_instructions(self.second)?; 62 | self.first_stats.update(first_instructions as f64); 63 | self.first_stats_count += 1; 64 | self.second_stats.update(second_instructions as f64); 65 | self.second_stats_count += 1; 66 | } 67 | 68 | let t = self.calculate_t(); 69 | 70 | // Return results when t value is above threshold 71 | if t >= self.t_threshold { 72 | Ok((t, DudeResult::Ok)) 73 | } 74 | // Check if we should give up 75 | else if self.first_stats_count > self.fail_min_samples && t <= self.t_fail { 76 | Ok((t, DudeResult::Err)) 77 | } else { 78 | // Neither success nor failure, keep going. 79 | Ok((t, DudeResult::Progress)) 80 | } 81 | } 82 | 83 | fn calculate_t(&self) -> f64 { 84 | let first_mean = self.first_stats.mean; 85 | let second_mean = self.second_stats.mean; 86 | 87 | let first_std_dev = self.first_stats.std_dev; 88 | let second_std_dev = self.second_stats.std_dev; 89 | 90 | let first_variance = first_std_dev * first_std_dev; 91 | let second_variance = second_std_dev * second_std_dev; 92 | 93 | let first_sample_size = self.first_stats_count as f64; 94 | let second_sample_size = self.second_stats_count as f64; 95 | 96 | let t = (first_mean - second_mean) 97 | / ((first_variance / first_sample_size) + (second_variance / second_sample_size)) 98 | .sqrt(); 99 | 100 | t.abs() 101 | } 102 | } 103 | 104 | #[cfg(test)] 105 | mod tests { 106 | // TODO: Create a test that uses a minimal hard-coded WAT. 107 | } 108 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | // This file contains all errors 2 | 3 | use failure::*; 4 | use std::convert::From; 5 | use std::io::Error as IOError; 6 | use wasmi::Error as WasmError; 7 | 8 | #[derive(Debug, Fail)] 9 | pub enum SideFuzzError { 10 | #[fail(display = "The first input and the second input are not the same size.")] 11 | InputsDifferentSizes, 12 | 13 | #[fail( 14 | display = "The input is of the wrong length for this fuzzing target. The target wants an input of {} bytes.", 15 | 0 16 | )] 17 | InputsWrongSize(usize), 18 | 19 | #[fail(display = "Could not read file: {}", 0)] 20 | CouldNotReadFile(IOError), 21 | 22 | #[fail(display = "wasm error: {}", 0)] 23 | WasmError(WasmError), 24 | 25 | #[fail(display = "wasm module expected to have 'memory' export")] 26 | WasmModuleNoMemory, 27 | 28 | #[fail(display = "wasm module exported non-memory to 'memory' export")] 29 | WasmModuleBadMemory, 30 | 31 | #[fail(display = "wasm module expected to have 'input_pointer' that returns an i32")] 32 | WasmModuleNoInputPointer, 33 | 34 | #[fail(display = "wasm module expected to have 'input_len' that returns an i32")] 35 | WasmModuleNoInputLen, 36 | 37 | #[fail(display = "wasm module expected to have 'fuzz' function export")] 38 | WasmModuleNoFuzz, 39 | 40 | #[fail(display = "wasm module input_pointer returned bad type, i32 expected.")] 41 | WasmModuleBadInputPointer, 42 | 43 | #[fail(display = "wasm module 'input_len' returned bad type, i32 expected.")] 44 | WasmModuleBadInpuLen, 45 | 46 | #[fail(display = "error writing input memory to wasm: {}", 0)] 47 | MemorySetError(WasmError), 48 | 49 | #[fail( 50 | display = "requested fuzzing input length of {} is too long. 1024 bytes is the maximum.", 51 | 0 52 | )] 53 | FuzzLenTooLong(u32), 54 | } 55 | 56 | impl From for SideFuzzError { 57 | fn from(error: IOError) -> Self { 58 | SideFuzzError::CouldNotReadFile(error) 59 | } 60 | } 61 | 62 | impl From for SideFuzzError { 63 | fn from(error: WasmError) -> Self { 64 | SideFuzzError::WasmError(error) 65 | } 66 | } -------------------------------------------------------------------------------- /src/fuzz.rs: -------------------------------------------------------------------------------- 1 | // This file contains the "fuzz" subcommand 2 | 3 | use crate::dudect::{DudeCT, DudeResult}; 4 | use crate::errors::SideFuzzError; 5 | use crate::optimizer::Optimizer; 6 | 7 | use crate::util::*; 8 | use crate::wasm::WasmModule; 9 | pub struct Fuzz { 10 | module: WasmModule, 11 | } 12 | 13 | impl Fuzz { 14 | pub fn new(module: WasmModule) -> Self { 15 | Fuzz { module } 16 | } 17 | 18 | pub fn from_file(filename: &str) -> Result { 19 | let module = WasmModule::from_file(filename)?; 20 | Ok(Self::new(module)) 21 | } 22 | 23 | pub fn run(&mut self) -> Result<(), SideFuzzError> { 24 | // Grab a copy of module bytes, we will pass this into DudeCT later 25 | let module_bytes = self.module.bytes(); 26 | 27 | // Print approximately fuzzing duration 28 | // duration = run-time * aprox-num-loops * num-generations-per-loop * population-size 29 | let duration = self.module.measure_time()? * 40.0 * 500.0 * 1000.0; 30 | println!("Fuzzing will take approximately {:.*}", 0, duration); 31 | 32 | let input_is_str = self.module.input_is_str(); 33 | let mut optimizer = Optimizer::new( 34 | self.module.fuzz_len(), 35 | |first: &[u8], second: &[u8]| { 36 | ScoredInputPair::generate( 37 | &mut self.module, 38 | first.to_vec(), 39 | second.to_vec(), 40 | input_is_str, 41 | ) 42 | }, 43 | input_is_str, 44 | ); 45 | 46 | println!("Evolving candidate input pairs"); 47 | let mut best = ScoredInputPair::default(); // defaults to score of zero. 48 | let mut moving_window = vec![0.0; 10]; // Moving window of size 10 49 | loop { 50 | // Check results once every 500 genearations 51 | for _ in 0..500 { 52 | optimizer.step(); 53 | } 54 | let population = optimizer.scored_population(); 55 | let pop_best = population[0].clone(); // Best of this population is ordered first. 56 | 57 | if pop_best.score != 0.0 { 58 | println!( 59 | "{} {} {}", 60 | pop_best.score, 61 | hex::encode(&population[0].pair.first), 62 | hex::encode(&population[0].pair.second) 63 | ); 64 | } else { 65 | println!("Looks constant-time so far..."); 66 | } 67 | 68 | // Adjust moving window 69 | moving_window.remove(0); 70 | moving_window.push(pop_best.score); 71 | 72 | if pop_best.score > best.score { 73 | best = pop_best; 74 | } 75 | 76 | if best.score != 0.0 { 77 | // Check the moving window is entirely the same as the best, this means we're maxed out. 78 | let mut local_optimum = true; 79 | for score in moving_window.iter() { 80 | if score != &best.score { 81 | local_optimum = false; 82 | break; 83 | } 84 | } 85 | 86 | if local_optimum { 87 | println!( 88 | "Checking {} {}", 89 | hex::encode(&best.pair.first), 90 | hex::encode(&best.pair.second) 91 | ); 92 | 93 | // Construct DudeCT 94 | // Return success on t = 4.5 (very high confidence) 95 | // Give up on t < 0.674 (50% confidence) when over 1 million samples. 96 | let mut dudect = DudeCT::new( 97 | 4.5, // Success t-value 98 | 0.674, // Give up t-value 99 | 100_000, // Give up min samples 100 | &best.pair.first, 101 | &best.pair.second, 102 | WasmModule::new(module_bytes.clone())?, 103 | )?; 104 | 105 | loop { 106 | let (t, result) = dudect.sample(10_000)?; 107 | let p = p_value_from_t_value(t); 108 | 109 | println!( 110 | "samples: {}, t-value: {}, confidence: {}%", 111 | dudect.len(), 112 | t, 113 | (1.0 - p) * 100.0 114 | ); 115 | 116 | match result { 117 | DudeResult::Ok => { 118 | println!( 119 | "Found timing difference of {} instructions between these two inputs with {}% confidence:\ninput 1: {}\ninput 2: {}", 120 | best.score, 121 | (1.0 - p) * 100.0, 122 | hex::encode(&best.pair.first), 123 | hex::encode(&best.pair.second) 124 | ); 125 | std::process::exit(0); 126 | } 127 | DudeResult::Err => { 128 | best = ScoredInputPair::default(); 129 | println!( 130 | "Candidate input pair rejected: t-statistic small after many samples. Continuing to evolve candidate inputs." 131 | ); 132 | break; 133 | } 134 | DudeResult::Progress => { 135 | continue; 136 | } 137 | } 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! SideFuzz is an adaptive fuzzer that uses a genetic-algorithim optimizer in combination with t-statistics to find side-channel (timing) vulnerabilities in cryptography compiled to wasm. 2 | //! 3 | //! See the [README](https://github.com/phayes/sidefuzz) for complete documentation. 4 | //! 5 | //! Creating a target in rust is done in the following way: 6 | //! 7 | //! ```rust,ignore 8 | //! // lib.rs 9 | //! #[no_mangle] 10 | //! pub extern "C" fn fuzz() { 11 | //! let input = sidefuzz::fetch_input(32); // 32 bytes of of fuzzing input as a &[u8] 12 | //! sidefuzz::black_box(my_hopefully_constant_fn(input)); 13 | //! } 14 | //! ``` 15 | //! ```toml 16 | //! # Cargo.toml 17 | //! [lib] 18 | //! crate-type = ["cdylib"] 19 | //! 20 | //! [dependencies] 21 | //! sidefuzz = "0.1.2" 22 | //! ``` 23 | //! Compile and fuzz the target like so: 24 | //! 25 | //! ```bash 26 | //! cargo build --release --target wasm32-unknown-unknown # Always build in release mode 27 | //! sidefuzz fuzz ./target/wasm32-unknown-unknown/release/my_target.wasm # Fuzzing! 28 | //! ``` 29 | 30 | // An implementation of dudect 31 | #[cfg(not(any(target_arch = "wasm32")))] 32 | pub(crate) mod dudect; 33 | 34 | // A genetic optimizer 35 | #[cfg(not(any(target_arch = "wasm32")))] 36 | pub(crate) mod optimizer; 37 | 38 | // The fuzz command 39 | #[cfg(not(any(target_arch = "wasm32")))] 40 | #[doc(hidden)] 41 | pub mod fuzz; 42 | 43 | // The check command 44 | #[cfg(not(any(target_arch = "wasm32")))] 45 | #[doc(hidden)] 46 | pub mod check; 47 | 48 | // The count command 49 | #[cfg(not(any(target_arch = "wasm32")))] 50 | #[doc(hidden)] 51 | pub mod count; 52 | 53 | // Wasm Module wrapper 54 | #[cfg(not(any(target_arch = "wasm32")))] 55 | pub(crate) mod wasm; 56 | 57 | // Errors 58 | #[cfg(not(any(target_arch = "wasm32")))] 59 | pub(crate) mod errors; 60 | 61 | // Misc utility functions and types 62 | #[cfg(not(any(target_arch = "wasm32")))] 63 | pub(crate) mod util; 64 | 65 | // This section contains utility functions used by WASM targets 66 | // ------------------------------------------------------------ 67 | 68 | /// A function that is opaque to the optimizer, to allow fuzzed functions to 69 | /// pretend to use outputs to assist in avoiding dead-code elimination. 70 | /// 71 | /// NOTE: We don't have a proper black box in stable Rust. This is 72 | /// a workaround implementation, that may have a too big performance overhead, 73 | /// depending on operation, or it may fail to properly avoid having code 74 | /// optimized out. It is good enough that it is used. 75 | #[inline(never)] 76 | pub fn black_box(dummy: D) -> D { 77 | unsafe { 78 | let ret = std::ptr::read_volatile(&dummy); 79 | std::mem::forget(dummy); 80 | ret 81 | } 82 | } 83 | 84 | // Assign a 1024 byte vector to hold inputs 85 | lazy_static::lazy_static! { 86 | static ref INPUT: Vec = vec![0; 1024]; 87 | } 88 | 89 | // The actual input length (generally less than 1024) 90 | static mut INPUT_LEN: i32 = 0; 91 | 92 | // Is the input a string? 93 | static mut INPUT_IS_STR: bool = false; 94 | 95 | /// Get an input of the desired length. 96 | /// This function should be called with a constant unchanging len argument. 97 | /// Calling it with different lengths will result in invalid fuzzing. 98 | /// 99 | /// If used, `fetch_input` should be used exclusively, and `fetch_str_input` should not be used. 100 | /// 101 | /// Example: 102 | /// ```ignore 103 | /// let input = sidefuzz::fetch_input(32); // get 32 bytes of input 104 | /// sidefuzz::black_box(my_contant_time_fn(input)); 105 | /// ``` 106 | /// 107 | // This is a VERY odd fuction that provides us with a really nice external API. 108 | // 1. It is called once before fuzzing starts in order to set the size of INPUT. 109 | // 2. After it is called once, we call input_pointer and input_len from the host to get a stable pointer to INPUT. 110 | // 3. Fuzzing starts, we write data to INPUT from the host, then call the exported `fuzz` function. 111 | pub fn fetch_input(len: i32) -> &'static [u8] { 112 | // This use of unsafe since wasm is single-threaded and nothing else is accessing INPUT_LEN. 113 | unsafe { 114 | if INPUT_LEN == 0 { 115 | INPUT_LEN = len; 116 | panic!("Input length successfully set. Panicking to unwind and stop execution."); 117 | } 118 | } 119 | 120 | &INPUT[0..len as usize] 121 | } 122 | 123 | /// Get an input of the desired length, as a string. 124 | /// This function should be called with a constant unchanging len argument. 125 | /// Calling it with different lengths will result in invalid fuzzing. 126 | /// 127 | /// If used, `fetch_str_input` should be used exclusively, and `fetch_input` should not be used. 128 | /// 129 | /// Example: 130 | /// ```ignore 131 | /// let input = sidefuzz::fetch_str_input(32); // get 32 bytes of input as a string 132 | /// sidefuzz::black_box(my_contant_time_fn(input)); 133 | /// ``` 134 | // 135 | // See `fetch_input` for some caveats on how this weird function is used 136 | pub fn fetch_str_input(len: i32) -> &'static str { 137 | // This use of unsafe since wasm is single-threaded and nothing else is accessing INPUT_LEN. 138 | unsafe { 139 | if INPUT_LEN == 0 { 140 | INPUT_LEN = len; 141 | INPUT_IS_STR = true; 142 | panic!("Input length successfully set. Panicking to unwind and stop execution."); 143 | } 144 | } 145 | 146 | unsafe { std::str::from_utf8_unchecked(&INPUT[0..len as usize]) } 147 | } 148 | 149 | /// Get a pointer to the input array 150 | /// This needs to be public so we can call it across host/wasm boundary, 151 | /// but it should be considered a "private" function to sidefuzz. 152 | /// It's API is not stable and may be subject to change 153 | #[doc(hidden)] 154 | #[no_mangle] 155 | pub extern "C" fn input_pointer() -> i32 { 156 | INPUT.as_ptr() as i32 157 | } 158 | 159 | /// Get the length of the input array 160 | /// This needs to be public so we can call it across host/wasm boundary, 161 | /// but it should be considered a "private" function to sidefuzz. 162 | /// It's API is not stable and may be subject to change 163 | #[doc(hidden)] 164 | #[no_mangle] 165 | pub extern "C" fn input_len() -> i32 { 166 | unsafe { INPUT_LEN } 167 | } 168 | 169 | /// Check if the input should be a string 170 | /// This needs to be public so we can call it across host/wasm boundary, 171 | /// but it should be considered a "private" function to sidefuzz. 172 | /// It's API is not stable and may be subject to change 173 | #[doc(hidden)] 174 | #[no_mangle] 175 | pub extern "C" fn input_is_str() -> i32 { 176 | if unsafe { INPUT_IS_STR } { 177 | return 1; 178 | } else { 179 | return 0; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg, SubCommand}; 2 | use failure::Error; 3 | 4 | 5 | use sidefuzz::check::Check; 6 | use sidefuzz::count::Count; 7 | use sidefuzz::fuzz::Fuzz; 8 | fn main() -> Result<(), Error> { 9 | color_backtrace::install(); 10 | 11 | let mut app = App::new("sidefuzz") 12 | .version("0.1.0") 13 | .author("Patrick Hayes ") 14 | .about("Fuzzes for timing side-channel vulnerabilities using wasm. \nhttps://github.com/phayes/sidefuzz") 15 | .arg( 16 | Arg::with_name("v") 17 | .short("v") 18 | .multiple(true) 19 | .help("Sets the level of verbosity"), 20 | ) 21 | .subcommand( 22 | SubCommand::with_name("fuzz") 23 | .about("fuzzes wasm file, generating variable-time input pairs") 24 | .arg( 25 | Arg::with_name("wasm-file") 26 | .help("wasm file fuzzing target") 27 | .required(true) 28 | .index(1), 29 | ), 30 | ) 31 | .subcommand( 32 | SubCommand::with_name("check") 33 | .about("Check wasm file with two inputs") 34 | .arg( 35 | Arg::with_name("wasm-file") 36 | .help("wasm file fuzzing target") 37 | .required(true) 38 | .index(1), 39 | ) 40 | .arg( 41 | Arg::with_name("input-1") 42 | .help("first input in hexedecimal format") 43 | .required(true) 44 | .index(2), 45 | ) 46 | .arg( 47 | Arg::with_name("input-2") 48 | .help("second input in hexedecimal format") 49 | .required(true) 50 | .index(3), 51 | ), 52 | ) 53 | .subcommand( 54 | SubCommand::with_name("count") 55 | .about("Count the number of instructions executed for a single input.") 56 | .arg( 57 | Arg::with_name("wasm-file") 58 | .help("wasm file fuzzing target") 59 | .required(true) 60 | .index(1), 61 | ) 62 | .arg( 63 | Arg::with_name("input") 64 | .help("Input in hexedecimal format") 65 | .required(true) 66 | .index(2), 67 | ) 68 | ); 69 | 70 | let matches = app.clone().get_matches(); 71 | 72 | // Fuzz command 73 | if let Some(sub_match) = matches.subcommand_matches("fuzz") { 74 | let filename = sub_match.value_of("wasm-file").unwrap(); 75 | let mut fuzz = match Fuzz::from_file(filename) { 76 | Ok(fuzz) => fuzz, 77 | Err(err) => { 78 | println!("Error: {}", err); 79 | std::process::exit(1); 80 | } 81 | }; 82 | 83 | let result = fuzz.run(); 84 | match result { 85 | Ok(_) => std::process::exit(0), 86 | Err(err) => { 87 | println!("Error: {}", err); 88 | std::process::exit(0); 89 | } 90 | } 91 | } 92 | 93 | // Check command 94 | if let Some(sub_match) = matches.subcommand_matches("check") { 95 | let filename = sub_match.value_of("wasm-file").unwrap(); 96 | 97 | let first = sub_match.value_of("input-1").unwrap(); 98 | let first = hex::decode(first)?; 99 | 100 | let second = sub_match.value_of("input-2").unwrap(); 101 | let second = hex::decode(second)?; 102 | 103 | let mut check = match Check::from_file(filename, first, second) { 104 | Ok(check) => check, 105 | Err(err) => { 106 | println!("Error: {}", err); 107 | std::process::exit(1); 108 | } 109 | }; 110 | 111 | let result = check.run(); 112 | match result { 113 | Ok(_) => std::process::exit(0), 114 | Err(err) => { 115 | println!("Error: {}", err); 116 | std::process::exit(0); 117 | } 118 | } 119 | } 120 | 121 | // Count command 122 | if let Some(sub_match) = matches.subcommand_matches("count") { 123 | let filename = sub_match.value_of("wasm-file").unwrap(); 124 | 125 | let input = sub_match.value_of("input").unwrap(); 126 | let input = hex::decode(input)?; 127 | 128 | let mut count = match Count::from_file(filename, input) { 129 | Ok(count) => count, 130 | Err(err) => { 131 | println!("Error: {}", err); 132 | std::process::exit(1); 133 | } 134 | }; 135 | 136 | count.run(); 137 | std::process::exit(0); 138 | } 139 | 140 | app.print_long_help()?; 141 | Ok(()) 142 | } -------------------------------------------------------------------------------- /src/optimizer.rs: -------------------------------------------------------------------------------- 1 | use crate::util::*; 2 | use rand::{seq::SliceRandom, Rng}; 3 | 4 | // Population size 5 | const POPULATION_SIZE: usize = 1000; 6 | 7 | // Mutation rate 8 | const MUTATION_RATE: f64 = 0.25; 9 | 10 | // Ratio of "large mutations" (random u8 replacement) vs "small mutations" u8 increment / decrement. 11 | const LARGE_MUTATION_RATIO: f64 = 0.25; 12 | 13 | // Directly clone this ratio of top performers 14 | const CLONE_RATIO: f64 = 0.05; 15 | 16 | // Breed from this top percentage of the population 17 | const BREEDING_POOL: f64 = 0.10; 18 | 19 | pub struct Optimizer 20 | where 21 | T: FnMut(&[u8], &[u8]) -> ScoredInputPair, 22 | { 23 | population: Vec, 24 | fitness: T, 25 | input_is_str: bool, 26 | } 27 | 28 | impl Optimizer 29 | where 30 | T: FnMut(&[u8], &[u8]) -> ScoredInputPair, 31 | { 32 | pub fn new(len: usize, fitness_function: T, input_is_str: bool) -> Self { 33 | Optimizer { 34 | population: inital_population(len, input_is_str), 35 | fitness: fitness_function, 36 | input_is_str, 37 | } 38 | } 39 | 40 | pub fn scored_population(&mut self) -> Vec { 41 | // Get fitness of all individuals 42 | let mut scored: Vec = Vec::with_capacity(self.population.len()); 43 | 44 | for individual in self.population.iter() { 45 | let score = (self.fitness)(&individual.first, &individual.second); 46 | scored.push(score); 47 | } 48 | 49 | // Sort most fit to least fit 50 | // Unwrap OK since score cannot be NAN. 51 | scored.sort_by(|a, b| b.score.partial_cmp(&a.score).unwrap()); 52 | 53 | scored 54 | } 55 | 56 | pub fn step(&mut self) { 57 | // Get fitness of all individuals 58 | let scored = self.scored_population(); 59 | 60 | // Calculate number to clone and number to breed 61 | let num_clone: usize = (POPULATION_SIZE as f64 * CLONE_RATIO) as usize; 62 | let breed_pool: usize = (POPULATION_SIZE as f64 * BREEDING_POOL) as usize; 63 | let breed_fill: usize = POPULATION_SIZE - num_clone; 64 | 65 | // Create the next generation 66 | let mut next_gen: Vec = Vec::with_capacity(self.population.len()); 67 | 68 | // Clone the top contenders 69 | for score in scored.iter().take(num_clone) { 70 | next_gen.push(score.pair.clone()); 71 | } 72 | 73 | // Breed and mutate the rest 74 | for _ in 0..breed_fill { 75 | // Select two individuals 76 | let parent_one = &scored[rand::thread_rng().gen_range(0, breed_pool)].pair; 77 | let parent_two = &scored[rand::thread_rng().gen_range(0, breed_pool)].pair; 78 | 79 | let mut child; 80 | if self.input_is_str { 81 | child = InputPair { 82 | first: breed_str_slice(&parent_one.first, &parent_two.first), 83 | second: breed_str_slice(&parent_one.second, &parent_two.second), 84 | is_str: self.input_is_str, 85 | }; 86 | } else { 87 | child = InputPair { 88 | first: breed_slice(&parent_one.first, &parent_two.first), 89 | second: breed_slice(&parent_one.second, &parent_two.second), 90 | is_str: self.input_is_str, 91 | }; 92 | } 93 | 94 | // Mutate 95 | if rand::thread_rng().gen_bool(MUTATION_RATE) { 96 | if rand::thread_rng().gen() { 97 | if self.input_is_str { 98 | mutate_str_slice(&mut child.first); 99 | } else { 100 | mutate_slice(&mut child.first); 101 | } 102 | } else { 103 | if self.input_is_str { 104 | mutate_str_slice(&mut child.second); 105 | } else { 106 | mutate_slice(&mut child.second); 107 | } 108 | } 109 | } 110 | 111 | next_gen.push(child); 112 | } 113 | 114 | self.population = next_gen; 115 | } 116 | } 117 | 118 | fn breed_slice(first: &[u8], second: &[u8]) -> Vec { 119 | let mut child: Vec = Vec::with_capacity(first.len()); 120 | for n in 0..first.len() { 121 | if rand::thread_rng().gen() { 122 | child.push(first[n]); 123 | } else { 124 | child.push(second[n]); 125 | } 126 | } 127 | 128 | child 129 | } 130 | 131 | fn breed_str_slice(first: &[u8], second: &[u8]) -> Vec { 132 | let mut child: Vec = breed_slice(first, second); 133 | 134 | // Mutate until it's valid 135 | loop { 136 | match std::str::from_utf8(&child) { 137 | Ok(_) => return child, 138 | Err(_) => {} 139 | } 140 | mutate_slice(&mut child); 141 | } 142 | } 143 | 144 | fn mutate_slice(slice: &mut [u8]) { 145 | // OK to unwrap here, slice should never be empty 146 | let mutating_gene = slice.choose_mut(&mut rand::thread_rng()).unwrap(); 147 | 148 | if rand::thread_rng().gen_bool(LARGE_MUTATION_RATIO) { 149 | // Large mutation, assign another random u8 150 | *mutating_gene = rand::thread_rng().gen(); 151 | } else { 152 | // Small mutation, increment or decrement 153 | if rand::thread_rng().gen() { 154 | *mutating_gene = mutating_gene.wrapping_add(1); 155 | } else { 156 | *mutating_gene = mutating_gene.wrapping_sub(1); 157 | } 158 | } 159 | } 160 | 161 | fn mutate_str_slice(slice: &mut [u8]) { 162 | loop { 163 | mutate_slice(slice); 164 | 165 | match std::str::from_utf8(slice) { 166 | Ok(_) => return, 167 | Err(_) => continue, 168 | } 169 | } 170 | } 171 | 172 | fn inital_population(len: usize, is_str: bool) -> Vec { 173 | let mut population = Vec::with_capacity(POPULATION_SIZE); 174 | for _ in 0..POPULATION_SIZE { 175 | if is_str { 176 | population.push(random_str_individual(len)); 177 | } else { 178 | population.push(random_individual(len)); 179 | } 180 | } 181 | population 182 | } 183 | 184 | fn random_individual(len: usize) -> InputPair { 185 | InputPair { 186 | first: (0..len).map(|_| rand::random::()).collect(), 187 | second: (0..len).map(|_| rand::random::()).collect(), 188 | is_str: false, 189 | } 190 | } 191 | 192 | fn random_str_individual(len: usize) -> InputPair { 193 | use rand::distributions::Alphanumeric; 194 | 195 | // This will create ascii strings, all under 127 in value, we can translate it right to bytes 196 | let first: String = rand::thread_rng() 197 | .sample_iter(&Alphanumeric) 198 | .take(len) 199 | .collect(); 200 | let second: String = rand::thread_rng() 201 | .sample_iter(&Alphanumeric) 202 | .take(len) 203 | .collect(); 204 | 205 | InputPair { 206 | first: first.into_bytes(), 207 | second: second.into_bytes(), 208 | is_str: true, 209 | } 210 | } 211 | 212 | #[cfg(test)] 213 | mod tests { 214 | use crate::optimizer::Optimizer; 215 | use crate::util::*; 216 | 217 | #[test] 218 | fn optimizer_test() { 219 | let target = b"GENETIC ALGOS!"; 220 | let mut optimizer = Optimizer::new( 221 | target.len(), 222 | |first: &[u8], second: &[u8]| { 223 | let mut score: f64 = 0.0; 224 | for item in [first, second].iter() { 225 | for (i, byte) in item.iter().enumerate() { 226 | let diff = if &target[i] > byte { 227 | target[i] - byte 228 | } else if byte > &target[i] { 229 | byte - target[i] 230 | } else { 231 | 0 232 | }; 233 | score = score - (diff as f64); 234 | } 235 | } 236 | ScoredInputPair { 237 | score, 238 | highest: 0.0, 239 | lowest: 0.0, 240 | pair: InputPair { 241 | first: first.to_vec(), 242 | second: second.to_vec(), 243 | is_str: false, 244 | }, 245 | } 246 | }, 247 | false, 248 | ); 249 | 250 | // Run one hundred generations 251 | for _ in 0..1000 { 252 | optimizer.step(); 253 | } 254 | 255 | // This will be sorted 256 | let population = optimizer.scored_population(); 257 | 258 | assert_eq!(population[0].pair.first, target); 259 | assert_eq!(population[0].pair.second, target); 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | // Misc utility functions used by various parts of the program 2 | 3 | use crate::wasm::WasmModule; 4 | use std::f64::{NAN, NEG_INFINITY}; 5 | 6 | #[derive(Debug, Clone, Default)] 7 | pub struct InputPair { 8 | pub first: Vec, 9 | pub second: Vec, 10 | pub is_str: bool, 11 | } 12 | 13 | #[derive(Debug, Clone, Default)] 14 | pub struct ScoredInputPair { 15 | pub score: f64, 16 | pub highest: f64, 17 | pub lowest: f64, 18 | pub pair: InputPair, 19 | } 20 | 21 | impl ScoredInputPair { 22 | pub fn generate( 23 | module: &mut WasmModule, 24 | first: Vec, 25 | second: Vec, 26 | is_str: bool, 27 | ) -> Self { 28 | // First 29 | let first_instructions = module.count_instructions(&first); 30 | let first_instructions = match first_instructions { 31 | Ok(count) => count, 32 | Err(_) => { 33 | // WASM trapped, score is negative infinity 34 | return ScoredInputPair { 35 | score: NEG_INFINITY, 36 | highest: NAN, 37 | lowest: NAN, 38 | pair: InputPair { 39 | first, 40 | second, 41 | is_str, 42 | }, 43 | }; 44 | } 45 | }; 46 | 47 | // Second 48 | let second_instructions = module.count_instructions(&second); 49 | let second_instructions = match second_instructions { 50 | Ok(count) => count, 51 | Err(_) => { 52 | // WASM trapped, score is negative infinity 53 | return ScoredInputPair { 54 | score: NEG_INFINITY, 55 | highest: NAN, 56 | lowest: NAN, 57 | pair: InputPair { 58 | first, 59 | second, 60 | is_str, 61 | }, 62 | }; 63 | } 64 | }; 65 | 66 | // Differences, highest, lowest etc. 67 | let highest; 68 | let lowest; 69 | if first_instructions >= second_instructions { 70 | highest = first_instructions; 71 | lowest = second_instructions; 72 | } else { 73 | highest = second_instructions; 74 | lowest = first_instructions; 75 | } 76 | let diff = highest - lowest; 77 | 78 | // TODO: Add Enum FirstHighest, SecondHighest and use to print 79 | 80 | ScoredInputPair { 81 | score: diff as f64, 82 | highest: highest as f64, 83 | lowest: lowest as f64, 84 | pair: InputPair { 85 | first, 86 | second, 87 | is_str, 88 | }, 89 | } 90 | } 91 | } 92 | 93 | // Given a t-value, the the p-value from it. 94 | // 95 | // This currently uses t-tables, in the future it will use an actual formula. 96 | pub(crate) fn p_value_from_t_value(t: f64) -> f64 { 97 | // TODO: use formula instead of table. 98 | 99 | if t <= 0.0 { 100 | return 1.0; // 0% confidence. 101 | } 102 | 103 | // Assume infinite degrees of freedom 104 | // Two tailed t test 105 | let t_table = vec![ 106 | (10.000, 0.0), // 100% confidence 107 | (3.91, 0.0001), 108 | (3.291, 0.001), 109 | (3.090, 0.002), 110 | (2.807, 0.005), 111 | (2.576, 0.01), 112 | (2.326, 0.02), 113 | (1.960, 0.05), 114 | (1.645, 0.1), 115 | (1.282, 0.2), 116 | (1.036, 0.3), 117 | (0.842, 0.4), 118 | (0.674, 0.5), 119 | (0.253, 0.6), 120 | (0.0, 1.0), // 0% confidence 121 | ]; 122 | 123 | for (t_value, p_value) in t_table { 124 | if t > t_value { 125 | return p_value; 126 | } 127 | } 128 | 129 | panic!("Invalid t value"); 130 | } 131 | -------------------------------------------------------------------------------- /src/wasm.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::SideFuzzError; 2 | use float_duration::{FloatDuration, TimePoint}; 3 | use std::fs::File; 4 | use std::io::prelude::*; 5 | use std::time::Instant; 6 | 7 | use wasmi::{ImportsBuilder, MemoryRef, Module, ModuleInstance, ModuleRef, NopExternals}; 8 | 9 | pub struct WasmModule { 10 | module: Vec, 11 | instance: ModuleRef, 12 | memory: MemoryRef, 13 | fuzz_ptr: u32, 14 | fuzz_len: u32, 15 | input_is_str: bool, 16 | } 17 | 18 | impl WasmModule { 19 | pub fn new(module: Vec) -> Result { 20 | let parsed = Module::from_buffer(&module).unwrap(); 21 | let instance = ModuleInstance::new(&parsed, &ImportsBuilder::default())?.assert_no_start(); 22 | 23 | // Get memory instance exported by name 'mem' from the module instance. 24 | let memory = instance.export_by_name("memory"); 25 | let memory = memory.ok_or(SideFuzzError::WasmModuleNoMemory)?; 26 | let memory = memory 27 | .as_memory() 28 | .ok_or(SideFuzzError::WasmModuleBadMemory)?; 29 | 30 | let mut wasm_module = Self { 31 | module: module, 32 | instance: instance, 33 | memory: memory.to_owned(), 34 | fuzz_ptr: 0, 35 | fuzz_len: 0, 36 | input_is_str: false, 37 | }; 38 | 39 | // Set input pointers 40 | wasm_module.set_input_pointer()?; 41 | 42 | // Prime lazy statics 43 | wasm_module.prime_lazy_statics()?; 44 | 45 | Ok(wasm_module) 46 | } 47 | 48 | pub fn from_file(filename: &str) -> Result { 49 | let mut file = File::open(filename)?; 50 | let mut buf = Vec::new(); 51 | file.read_to_end(&mut buf)?; 52 | Ok(Self::new(buf)?) 53 | } 54 | 55 | pub fn fuzz_len(&self) -> usize { 56 | self.fuzz_len as usize 57 | } 58 | 59 | pub fn input_is_str(&self) -> bool { 60 | self.input_is_str 61 | } 62 | 63 | pub fn bytes(&self) -> Vec { 64 | self.module.clone() 65 | } 66 | 67 | // Count instructions for a given input 68 | pub fn count_instructions(&mut self, input: &[u8]) -> Result { 69 | self.memory 70 | .set(self.fuzz_ptr, input) 71 | .map_err(|e| SideFuzzError::MemorySetError(e))?; 72 | wasmi::reset_instruction_count(); 73 | let result = self.instance.invoke_export("fuzz", &[], &mut NopExternals); 74 | if let Err(err) = result { 75 | // If we've got a MemoryAccessOutOfBounds error, then we've corrupted our memory. 76 | // In a real application this would be a crash, so reboot the instance and start over. 77 | if let wasmi::Error::Trap(trap) = &err { 78 | if let wasmi::TrapKind::MemoryAccessOutOfBounds = trap.kind() { 79 | self.reboot(); 80 | } 81 | } 82 | return Err(SideFuzzError::WasmError(err)); 83 | } 84 | let count = wasmi::get_instruction_count(); 85 | 86 | Ok(count) 87 | } 88 | 89 | // Restart / Reboot the instance 90 | fn reboot(&mut self) { 91 | // This should be ok to expect here since the module has already been instantiated previously. 92 | let new = Self::new(self.module.clone()).expect("Could not reboot wasm module instance."); 93 | self.instance = new.instance; 94 | self.memory = new.memory; 95 | } 96 | 97 | // Measure and report the running time for a single execution 98 | pub fn measure_time(&mut self) -> Result { 99 | let input: Vec = (0..self.fuzz_len).map(|_| rand::random::()).collect(); 100 | let start_time = Instant::now(); 101 | self.count_instructions(&input)?; 102 | let end_time = Instant::now(); 103 | 104 | Ok(end_time.float_duration_since(start_time).unwrap()) 105 | } 106 | 107 | // Prime lazy statics 108 | pub fn prime_lazy_statics(&mut self) -> Result<(), SideFuzzError> { 109 | // Prime until it completes successfully (limited to 100 attemps). 110 | let mut i = 0; 111 | loop { 112 | let input: Vec = (0..self.fuzz_len).map(|_| rand::random::()).collect(); 113 | let result = self.count_instructions(&input); 114 | if result.is_ok() { 115 | return Ok(()); 116 | } 117 | i += 1; 118 | if i >= 100 { 119 | return Err(result.unwrap_err()); 120 | } 121 | } 122 | } 123 | 124 | // Set the input fuzz length 125 | fn set_input_pointer(&mut self) -> Result<(), SideFuzzError> { 126 | // Call "sidefuzz" to prime INPUT static global and set it's length 127 | let _ = crate::black_box(self.count_instructions(&vec![])); 128 | 129 | // Call the "input_pointer" exported function to get the pointer to the input 130 | let input_pointer = self 131 | .instance 132 | .invoke_export("input_pointer", &[], &mut NopExternals)? 133 | .ok_or(SideFuzzError::WasmModuleNoInputPointer)?; 134 | 135 | // Call the "input_len" exported function to get the input length 136 | let input_len = self 137 | .instance 138 | .invoke_export("input_len", &[], &mut NopExternals)? 139 | .ok_or(SideFuzzError::WasmModuleNoInputLen)?; 140 | 141 | // Call the "input_is_str" exported function to check if input is a string 142 | let input_is_str = self 143 | .instance 144 | .invoke_export("input_is_str", &[], &mut NopExternals)? 145 | .ok_or(SideFuzzError::WasmModuleNoInputLen)?; 146 | 147 | let input_pointer = match input_pointer { 148 | wasmi::RuntimeValue::I32(inner) => inner, 149 | _ => { 150 | return Err(SideFuzzError::WasmModuleBadInputPointer); 151 | } 152 | }; 153 | 154 | let input_len = match input_len { 155 | wasmi::RuntimeValue::I32(inner) => inner, 156 | _ => { 157 | return Err(SideFuzzError::WasmModuleBadInpuLen); 158 | } 159 | }; 160 | if input_len > 1024 { 161 | return Err(SideFuzzError::FuzzLenTooLong(input_len as u32)); 162 | } 163 | 164 | let input_is_str = match input_is_str { 165 | wasmi::RuntimeValue::I32(inner) => inner > 0, 166 | _ => { 167 | return Err(SideFuzzError::WasmModuleBadInpuLen); 168 | } 169 | }; 170 | 171 | self.fuzz_ptr = input_pointer as u32; 172 | self.fuzz_len = input_len as u32; 173 | self.input_is_str = input_is_str; 174 | 175 | Ok(()) 176 | } 177 | } 178 | 179 | impl Clone for WasmModule { 180 | fn clone(&self) -> Self { 181 | // This should be ok to expect here since the module has already been instantiated previously. 182 | Self::new(self.module.clone()).expect("Unable to clone wasm module") 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /vendor/wasmi/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style=space 4 | indent_size = 4 5 | end_of_line=lf 6 | charset=utf-8 7 | trim_trailing_whitespace=true 8 | max_line_length=120 9 | insert_final_newline=true 10 | -------------------------------------------------------------------------------- /vendor/wasmi/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target/ 3 | **/*.rs.bk 4 | Cargo.lock 5 | spec/target 6 | -------------------------------------------------------------------------------- /vendor/wasmi/.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: required 3 | language: 4 | - rust 5 | - cpp 6 | rust: 7 | - nightly 8 | - stable 9 | matrix: 10 | allow_failures: 11 | - rust: nightly 12 | addons: 13 | apt: 14 | sources: 15 | - ubuntu-toolchain-r-test 16 | packages: 17 | - gcc-8 18 | - g++-8 19 | - cmake 20 | env: 21 | - CC=/usr/bin/gcc-8 CXX=/usr/bin/g++-8 22 | 23 | install: 24 | - if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then rustup target add wasm32-unknown-unknown; fi 25 | - rustup component add rustfmt 26 | script: 27 | - cargo fmt --all -- --check 28 | # Make sure nightly targets are not broken. 29 | - if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo check --tests --manifest-path=fuzz/Cargo.toml; fi 30 | - if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo check --benches --manifest-path=benches/Cargo.toml; fi 31 | # Make sure `no_std` version checks. 32 | - if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo +nightly check --no-default-features --features core; fi 33 | - ./test.sh 34 | - ./doc.sh 35 | after_success: | 36 | # Build documentation and deploy it to github pages. 37 | [ $TRAVIS_BRANCH = master ] && 38 | [ $TRAVIS_PULL_REQUEST = false ] && 39 | echo "" > target/doc/index.html && 40 | sudo pip install ghp-import && 41 | ghp-import -n target/doc && 42 | git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages 43 | cache: cargo 44 | before_cache: 45 | # Travis can't cache files that are not readable by "others" 46 | - chmod -R a+r $HOME/.cargo 47 | -------------------------------------------------------------------------------- /vendor/wasmi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasmi" 3 | version = "99.0.0-vendored" 4 | authors = ["Nikolay Volf ", "Svyatoslav Nikolsky ", "Sergey Pepyakin "] 5 | license = "MIT/Apache-2.0" 6 | readme = "README.md" 7 | repository = "https://github.com/paritytech/wasmi" 8 | documentation = "https://paritytech.github.io/wasmi/" 9 | description = "WebAssembly interpreter" 10 | keywords = ["wasm", "webassembly", "bytecode", "interpreter"] 11 | exclude = [ "/res/*", "/tests/*", "/fuzz/*", "/benches/*" ] 12 | 13 | [dependencies] 14 | wasmi-validation = { path = "validation", default-features = false } 15 | parity-wasm = { version = "0.31", default-features = false } 16 | hashbrown = { version = "0.1.8", optional = true } 17 | memory_units = "0.3.0" 18 | libm = { version = "0.1.2", optional = true } 19 | 20 | [dev-dependencies] 21 | assert_matches = "1.1" 22 | rand = "0.4.2" 23 | wabt = "0.6" 24 | 25 | [features] 26 | default = ["std"] 27 | # Disable for no_std support 28 | std = [ 29 | "parity-wasm/std", 30 | "wasmi-validation/std", 31 | ] 32 | # Enable for no_std support 33 | # hashbrown only works on no_std 34 | core = [ 35 | "wasmi-validation/core", 36 | "hashbrown/nightly", 37 | "libm" 38 | ] 39 | 40 | [workspace] 41 | members = ["validation"] 42 | -------------------------------------------------------------------------------- /vendor/wasmi/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Nikolay Volf 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /vendor/wasmi/README.md: -------------------------------------------------------------------------------- 1 | ## This is a custom patched version of wasmi, customized for wasm-sidefuzz, that allows for instruction counting 2 | 3 | [![crates.io link](https://img.shields.io/crates/v/wasmi.svg)](https://crates.io/crates/wasmi) 4 | [![Build Status](https://travis-ci.org/paritytech/wasmi.svg?branch=master)](https://travis-ci.org/paritytech/wasmi) 5 | 6 | # `wasmi` 7 | 8 | `wasmi` - a Wasm interpreter. 9 | 10 | `wasmi` was conceived as a component of [parity-ethereum](https://github.com/paritytech/parity-ethereum) (ethereum-like contracts in wasm) and [substrate](https://github.com/paritytech/substrate). These projects are related to blockchain and require a high degree of correctness, even if that might be over conservative. This specifically means that we are not trying to be involved in any implementation of any of work-in-progress Wasm proposals. We are also trying to be as close as possible to the spec, which means we are trying to avoid features that is not directly supported by the spec. This means that it is flexible on the one hand and on the other hand there shouldn't be a problem migrating to another spec compilant execution engine. 11 | 12 | With all that said, `wasmi` should be a good option for initial prototyping. 13 | 14 | # Build & Test 15 | 16 | As `wasmi` contains a git submodule, you need to use `--recursive` for cloning or to checkout the submodule explicitly, otherwise the testing would fail. 17 | 18 | ``` 19 | git clone https://github.com/paritytech/wasmi.git --recursive 20 | cd wasmi 21 | cargo build 22 | cargo test 23 | ``` 24 | 25 | # `no_std` support 26 | 27 | This crate supports `no_std` environments. 28 | Enable the `core` feature and disable default features: 29 | 30 | ```toml 31 | [dependencies] 32 | parity-wasm = { 33 | version = "0.31", 34 | default-features = false, 35 | features = "core" 36 | } 37 | ``` 38 | 39 | The `core` feature requires the `core` and `alloc` libraries and a nightly compiler. 40 | Also, code related to `std::error` is disabled. 41 | 42 | Floating point operations in `no_std` use [`libm`](https://crates.io/crates/libm), which sometimes panics in debug mode (https://github.com/japaric/libm/issues/4). 43 | So make sure to either use release builds or avoid WASM with floating point operations, for example by using [`deny_floating_point`](https://docs.rs/wasmi/0.4.0/wasmi/struct.Module.html#method.deny_floating_point). 44 | 45 | # License 46 | 47 | `wasmi` is primarily distributed under the terms of both the MIT 48 | license and the Apache License (Version 2.0), at your choice. 49 | 50 | See LICENSE-APACHE, and LICENSE-MIT for details. 51 | 52 | ## Contribution 53 | 54 | Unless you explicitly state otherwise, any contribution intentionally submitted 55 | for inclusion in `wasmi` by you, as defined in the Apache-2.0 license, shall be 56 | dual licensed as above, without any additional terms or conditions. 57 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | *.trace 3 | 4 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "benches" 3 | version = "0.1.0" 4 | authors = ["Sergey Pepyakin "] 5 | 6 | [dependencies] 7 | wasmi = { path = ".." } 8 | assert_matches = "1.2" 9 | wabt = "0.6" 10 | 11 | [profile.bench] 12 | debug = true 13 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::process; 3 | 4 | fn main() { 5 | println!("cargo:rerun-if-changed=./wasm-kernel/"); 6 | 7 | // The CARGO environment variable provides a path to the executable that 8 | // runs this build process. 9 | let cargo_bin = env::var("CARGO").expect("CARGO env variable should be defined"); 10 | 11 | // Build a release version of wasm-kernel. The code in the output wasm binary 12 | // will be used in benchmarks. 13 | let output = process::Command::new(cargo_bin) 14 | .arg("build") 15 | .arg("--target=wasm32-unknown-unknown") 16 | .arg("--release") 17 | .arg("--manifest-path=./wasm-kernel/Cargo.toml") 18 | .arg("--verbose") 19 | .output() 20 | .expect("failed to execute `cargo`"); 21 | 22 | if !output.status.success() { 23 | let msg = format!( 24 | "status: {status}\nstdout: {stdout}\nstderr: {stderr}\n", 25 | status = output.status, 26 | stdout = String::from_utf8_lossy(&output.stdout), 27 | stderr = String::from_utf8_lossy(&output.stderr), 28 | ); 29 | panic!("{}", msg); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | extern crate wasmi; 5 | #[macro_use] 6 | extern crate assert_matches; 7 | extern crate wabt; 8 | 9 | use std::error; 10 | use std::fs::File; 11 | use wasmi::{ImportsBuilder, Module, ModuleInstance, NopExternals, RuntimeValue}; 12 | 13 | use test::Bencher; 14 | 15 | // Load a module from a file. 16 | fn load_from_file(filename: &str) -> Result> { 17 | use std::io::prelude::*; 18 | let mut file = File::open(filename)?; 19 | let mut buf = Vec::new(); 20 | file.read_to_end(&mut buf)?; 21 | Ok(Module::from_buffer(buf)?) 22 | } 23 | 24 | const REVCOMP_INPUT: &'static [u8] = include_bytes!("./revcomp-input.txt"); 25 | const REVCOMP_OUTPUT: &'static [u8] = include_bytes!("./revcomp-output.txt"); 26 | 27 | #[bench] 28 | fn bench_tiny_keccak(b: &mut Bencher) { 29 | let wasm_kernel = load_from_file( 30 | "./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm", 31 | ).expect("failed to load wasm_kernel. Is `build.rs` broken?"); 32 | 33 | let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default()) 34 | .expect("failed to instantiate wasm module") 35 | .assert_no_start(); 36 | 37 | let test_data_ptr = assert_matches!( 38 | instance.invoke_export("prepare_tiny_keccak", &[], &mut NopExternals), 39 | Ok(Some(v @ RuntimeValue::I32(_))) => v 40 | ); 41 | 42 | b.iter(|| { 43 | instance 44 | .invoke_export("bench_tiny_keccak", &[test_data_ptr], &mut NopExternals) 45 | .unwrap(); 46 | }); 47 | } 48 | 49 | #[bench] 50 | fn bench_rev_comp(b: &mut Bencher) { 51 | let wasm_kernel = load_from_file( 52 | "./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm", 53 | ).expect("failed to load wasm_kernel. Is `build.rs` broken?"); 54 | 55 | let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default()) 56 | .expect("failed to instantiate wasm module") 57 | .assert_no_start(); 58 | 59 | // Allocate buffers for the input and output. 60 | let test_data_ptr: RuntimeValue = { 61 | let input_size = RuntimeValue::I32(REVCOMP_INPUT.len() as i32); 62 | assert_matches!( 63 | instance.invoke_export("prepare_rev_complement", &[input_size], &mut NopExternals), 64 | Ok(Some(v @ RuntimeValue::I32(_))) => v, 65 | "", 66 | ) 67 | }; 68 | 69 | // Get the pointer to the input buffer. 70 | let input_data_mem_offset = assert_matches!( 71 | instance.invoke_export("rev_complement_input_ptr", &[test_data_ptr], &mut NopExternals), 72 | Ok(Some(RuntimeValue::I32(v))) => v as u32, 73 | "", 74 | ); 75 | 76 | // Copy test data inside the wasm memory. 77 | let memory = instance.export_by_name("memory") 78 | .expect("Expected export with a name 'memory'") 79 | .as_memory() 80 | .expect("'memory' should be a memory instance") 81 | .clone(); 82 | memory 83 | .set(input_data_mem_offset, REVCOMP_INPUT) 84 | .expect("can't load test data into a wasm memory"); 85 | 86 | b.iter(|| { 87 | instance 88 | .invoke_export("bench_rev_complement", &[test_data_ptr], &mut NopExternals) 89 | .unwrap(); 90 | }); 91 | 92 | // Verify the result. 93 | let output_data_mem_offset = assert_matches!( 94 | instance.invoke_export("rev_complement_output_ptr", &[test_data_ptr], &mut NopExternals), 95 | Ok(Some(RuntimeValue::I32(v))) => v as u32, 96 | "", 97 | ); 98 | let result = memory 99 | .get(output_data_mem_offset, REVCOMP_OUTPUT.len()) 100 | .expect("can't get result data from a wasm memory"); 101 | assert_eq!(&*result, REVCOMP_OUTPUT); 102 | } 103 | 104 | #[bench] 105 | fn bench_regex_redux(b: &mut Bencher) { 106 | let wasm_kernel = load_from_file( 107 | "./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm", 108 | ).expect("failed to load wasm_kernel. Is `build.rs` broken?"); 109 | 110 | let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default()) 111 | .expect("failed to instantiate wasm module") 112 | .assert_no_start(); 113 | 114 | // Allocate buffers for the input and output. 115 | let test_data_ptr: RuntimeValue = { 116 | let input_size = RuntimeValue::I32(REVCOMP_INPUT.len() as i32); 117 | assert_matches!( 118 | instance.invoke_export("prepare_regex_redux", &[input_size], &mut NopExternals), 119 | Ok(Some(v @ RuntimeValue::I32(_))) => v, 120 | "", 121 | ) 122 | }; 123 | 124 | // Get the pointer to the input buffer. 125 | let input_data_mem_offset = assert_matches!( 126 | instance.invoke_export("regex_redux_input_ptr", &[test_data_ptr], &mut NopExternals), 127 | Ok(Some(RuntimeValue::I32(v))) => v as u32, 128 | "", 129 | ); 130 | 131 | // Copy test data inside the wasm memory. 132 | let memory = instance.export_by_name("memory") 133 | .expect("Expected export with a name 'memory'") 134 | .as_memory() 135 | .expect("'memory' should be a memory instance") 136 | .clone(); 137 | memory 138 | .set(input_data_mem_offset, REVCOMP_INPUT) 139 | .expect("can't load test data into a wasm memory"); 140 | 141 | b.iter(|| { 142 | instance 143 | .invoke_export("bench_regex_redux", &[test_data_ptr], &mut NopExternals) 144 | .unwrap(); 145 | }); 146 | } 147 | 148 | #[bench] 149 | fn fac_recursive(b: &mut Bencher) { 150 | let wasm = wabt::wat2wasm( 151 | r#" 152 | ;; Recursive factorial 153 | (func (export "fac-rec") (param i64) (result i64) 154 | (if (result i64) (i64.eq (get_local 0) (i64.const 0)) 155 | (then (i64.const 1)) 156 | (else 157 | (i64.mul (get_local 0) (call 0 (i64.sub (get_local 0) (i64.const 1)))) 158 | ) 159 | ) 160 | ) 161 | "# 162 | ).unwrap(); 163 | 164 | let module = Module::from_buffer(&wasm).unwrap(); 165 | 166 | let instance = ModuleInstance::new(&module, &ImportsBuilder::default()) 167 | .expect("failed to instantiate wasm module") 168 | .assert_no_start(); 169 | 170 | b.iter(|| { 171 | let value = instance 172 | .invoke_export("fac-rec", &[RuntimeValue::I64(25)], &mut NopExternals); 173 | assert_matches!(value, Ok(Some(RuntimeValue::I64(7034535277573963776)))); 174 | }); 175 | } 176 | 177 | #[bench] 178 | fn fac_opt(b: &mut Bencher) { 179 | let wasm = wabt::wat2wasm( 180 | r#" 181 | ;; Optimized factorial. 182 | (func (export "fac-opt") (param i64) (result i64) 183 | (local i64) 184 | (set_local 1 (i64.const 1)) 185 | (block 186 | (br_if 0 (i64.lt_s (get_local 0) (i64.const 2))) 187 | (loop 188 | (set_local 1 (i64.mul (get_local 1) (get_local 0))) 189 | (set_local 0 (i64.add (get_local 0) (i64.const -1))) 190 | (br_if 0 (i64.gt_s (get_local 0) (i64.const 1))) 191 | ) 192 | ) 193 | (get_local 1) 194 | ) 195 | "# 196 | ).unwrap(); 197 | 198 | let module = Module::from_buffer(&wasm).unwrap(); 199 | 200 | let instance = ModuleInstance::new(&module, &ImportsBuilder::default()) 201 | .expect("failed to instantiate wasm module") 202 | .assert_no_start(); 203 | 204 | b.iter(|| { 205 | let value = instance 206 | .invoke_export("fac-opt", &[RuntimeValue::I64(25)], &mut NopExternals); 207 | assert_matches!(value, Ok(Some(RuntimeValue::I64(7034535277573963776)))); 208 | }); 209 | } 210 | 211 | // This is used for testing overhead of a function call 212 | // is not too large. 213 | #[bench] 214 | fn recursive_ok(b: &mut Bencher) { 215 | let wasm = wabt::wat2wasm( 216 | r#" 217 | (module 218 | (func $call (export "call") (param i32) (result i32) 219 | block (result i32) 220 | get_local 0 221 | get_local 0 222 | i32.eqz 223 | br_if 0 224 | 225 | i32.const 1 226 | i32.sub 227 | call $call 228 | end 229 | ) 230 | ) 231 | "# 232 | ).unwrap(); 233 | let module = Module::from_buffer(&wasm).unwrap(); 234 | 235 | let instance = ModuleInstance::new(&module, &ImportsBuilder::default()) 236 | .expect("failed to instantiate wasm module") 237 | .assert_no_start(); 238 | 239 | b.iter(|| { 240 | let value = instance 241 | .invoke_export("call", &[RuntimeValue::I32(8000)], &mut NopExternals); 242 | assert_matches!(value, Ok(Some(RuntimeValue::I32(0)))); 243 | }); 244 | } 245 | 246 | #[bench] 247 | fn recursive_trap(b: &mut Bencher) { 248 | let wasm = wabt::wat2wasm( 249 | r#" 250 | (module 251 | (func $call (export "call") (param i32) (result i32) 252 | block (result i32) 253 | get_local 0 254 | get_local 0 255 | i32.eqz 256 | br_if 0 257 | 258 | i32.const 1 259 | i32.sub 260 | call $call 261 | end 262 | unreachable 263 | ) 264 | ) 265 | "# 266 | ).unwrap(); 267 | let module = Module::from_buffer(&wasm).unwrap(); 268 | 269 | let instance = ModuleInstance::new(&module, &ImportsBuilder::default()) 270 | .expect("failed to instantiate wasm module") 271 | .assert_no_start(); 272 | 273 | b.iter(|| { 274 | let value = instance 275 | .invoke_export("call", &[RuntimeValue::I32(1000)], &mut NopExternals); 276 | assert_matches!(value, Err(_)); 277 | }); 278 | } 279 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/src/revcomp-input.txt: -------------------------------------------------------------------------------- 1 | >ONE Homo sapiens alu 2 | GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA 3 | TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT 4 | AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG 5 | GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG 6 | CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT 7 | GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA 8 | GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA 9 | TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG 10 | AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA 11 | GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT 12 | AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC 13 | AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG 14 | GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC 15 | CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG 16 | AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT 17 | TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA 18 | TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT 19 | GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG 20 | TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT 21 | CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG 22 | CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG 23 | TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA 24 | CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG 25 | AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG 26 | GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC 27 | TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA 28 | TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA 29 | GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT 30 | GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC 31 | ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT 32 | TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC 33 | CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG 34 | CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG 35 | GGCGACAGAGCGAGACTCCG 36 | >TWO IUB ambiguity codes 37 | cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg 38 | tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa 39 | NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt 40 | cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga 41 | gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa 42 | HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca 43 | tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt 44 | tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt 45 | acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct 46 | tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt 47 | gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa 48 | accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt 49 | RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt 50 | tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag 51 | cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg 52 | ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat 53 | actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg 54 | YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa 55 | KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata 56 | aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa 57 | aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg 58 | gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc 59 | tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK 60 | tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt 61 | ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg 62 | ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa 63 | BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt 64 | aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc 65 | tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc 66 | cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac 67 | aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga 68 | tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga 69 | aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD 70 | gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg 71 | ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV 72 | taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa 73 | ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat 74 | gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg 75 | gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa 76 | tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt 77 | tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt 78 | taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca 79 | cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag 80 | aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt 81 | cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt 82 | ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW 83 | attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag 84 | ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa 85 | attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc 86 | tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta 87 | >THREE Homo sapiens frequency 88 | aacacttcaccaggtatcgtgaaggctcaagattacccagagaacctttgcaatataaga 89 | atatgtatgcagcattaccctaagtaattatattctttttctgactcaaagtgacaagcc 90 | ctagtgtatattaaatcggtatatttgggaaattcctcaaactatcctaatcaggtagcc 91 | atgaaagtgatcaaaaaagttcgtacttataccatacatgaattctggccaagtaaaaaa 92 | tagattgcgcaaaattcgtaccttaagtctctcgccaagatattaggatcctattactca 93 | tatcgtgtttttctttattgccgccatccccggagtatctcacccatccttctcttaaag 94 | gcctaatattacctatgcaaataaacatatattgttgaaaattgagaacctgatcgtgat 95 | tcttatgtgtaccatatgtatagtaatcacgcgactatatagtgctttagtatcgcccgt 96 | gggtgagtgaatattctgggctagcgtgagatagtttcttgtcctaatatttttcagatc 97 | gaatagcttctatttttgtgtttattgacatatgtcgaaactccttactcagtgaaagtc 98 | atgaccagatccacgaacaatcttcggaatcagtctcgttttacggcggaatcttgagtc 99 | taacttatatcccgtcgcttactttctaacaccccttatgtatttttaaaattacgttta 100 | ttcgaacgtacttggcggaagcgttattttttgaagtaagttacattgggcagactcttg 101 | acattttcgatacgactttctttcatccatcacaggactcgttcgtattgatatcagaag 102 | ctcgtgatgattagttgtcttctttaccaatactttgaggcctattctgcgaaatttttg 103 | ttgccctgcgaacttcacataccaaggaacacctcgcaacatgccttcatatccatcgtt 104 | cattgtaattcttacacaatgaatcctaagtaattacatccctgcgtaaaagatggtagg 105 | ggcactgaggatatattaccaagcatttagttatgagtaatcagcaatgtttcttgtatt 106 | aagttctctaaaatagttacatcgtaatgttatctcgggttccgcgaataaacgagatag 107 | attcattatatatggccctaagcaaaaacctcctcgtattctgttggtaattagaatcac 108 | acaatacgggttgagatattaattatttgtagtacgaagagatataaaaagatgaacaat 109 | tactcaagtcaagatgtatacgggatttataataaaaatcgggtagagatctgctttgca 110 | attcagacgtgccactaaatcgtaatatgtcgcgttacatcagaaagggtaactattatt 111 | aattaataaagggcttaatcactacatattagatcttatccgatagtcttatctattcgt 112 | tgtatttttaagcggttctaattcagtcattatatcagtgctccgagttctttattattg 113 | ttttaaggatgacaaaatgcctcttgttataacgctgggagaagcagactaagagtcgga 114 | gcagttggtagaatgaggctgcaaaagacggtctcgacgaatggacagactttactaaac 115 | caatgaaagacagaagtagagcaaagtctgaagtggtatcagcttaattatgacaaccct 116 | taatacttccctttcgccgaatactggcgtggaaaggttttaaaagtcgaagtagttaga 117 | ggcatctctcgctcataaataggtagactactcgcaatccaatgtgactatgtaatactg 118 | ggaacatcagtccgcgatgcagcgtgtttatcaaccgtccccactcgcctggggagacat 119 | gagaccacccccgtggggattattagtccgcagtaatcgactcttgacaatccttttcga 120 | ttatgtcatagcaatttacgacagttcagcgaagtgactactcggcgaaatggtattact 121 | aaagcattcgaacccacatgaatgtgattcttggcaatttctaatccactaaagcttttc 122 | cgttgaatctggttgtagatatttatataagttcactaattaagatcacggtagtatatt 123 | gatagtgatgtctttgcaagaggttggccgaggaatttacggattctctattgatacaat 124 | ttgtctggcttataactcttaaggctgaaccaggcgtttttagacgacttgatcagctgt 125 | tagaatggtttggactccctctttcatgtcagtaacatttcagccgttattgttacgata 126 | tgcttgaacaatattgatctaccacacacccatagtatattttataggtcatgctgttac 127 | ctacgagcatggtattccacttcccattcaatgagtattcaacatcactagcctcagaga 128 | tgatgacccacctctaataacgtcacgttgcggccatgtgaaacctgaacttgagtagac 129 | gatatcaagcgctttaaattgcatataacatttgagggtaaagctaagcggatgctttat 130 | ataatcaatactcaataataagatttgattgcattttagagttatgacacgacatagttc 131 | actaacgagttactattcccagatctagactgaagtactgatcgagacgatccttacgtc 132 | gatgatcgttagttatcgacttaggtcgggtctctagcggtattggtacttaaccggaca 133 | ctatactaataacccatgatcaaagcataacagaatacagacgataatttcgccaacata 134 | tatgtacagaccccaagcatgagaagctcattgaaagctatcattgaagtcccgctcaca 135 | atgtgtcttttccagacggtttaactggttcccgggagtcctggagtttcgacttacata 136 | aatggaaacaatgtattttgctaatttatctatagcgtcatttggaccaatacagaatat 137 | tatgttgcctagtaatccactataacccgcaagtgctgatagaaaatttttagacgattt 138 | ataaatgccccaagtatccctcccgtgaatcctccgttatactaattagtattcgttcat 139 | acgtataccgcgcatatatgaacatttggcgataaggcgcgtgaattgttacgtgacaga 140 | gatagcagtttcttgtgatatggttaacagacgtacatgaagggaaactttatatctata 141 | gtgatgcttccgtagaaataccgccactggtctgccaatgatgaagtatgtagctttagg 142 | tttgtactatgaggctttcgtttgtttgcagagtataacagttgcgagtgaaaaaccgac 143 | gaatttatactaatacgctttcactattggctacaaaatagggaagagtttcaatcatga 144 | gagggagtatatggatgctttgtagctaaaggtagaacgtatgtatatgctgccgttcat 145 | tcttgaaagatacataagcgataagttacgacaattataagcaacatccctaccttcgta 146 | acgatttcactgttactgcgcttgaaatacactatggggctattggcggagagaagcaga 147 | tcgcgccgagcatatacgagacctataatgttgatgatagagaaggcgtctgaattgata 148 | catcgaagtacactttctttcgtagtatctctcgtcctctttctatctccggacacaaga 149 | attaagttatatatatagagtcttaccaatcatgttgaatcctgattctcagagttcttt 150 | ggcgggccttgtgatgactgagaaacaatgcaatattgctccaaatttcctaagcaaatt 151 | ctcggttatgttatgttatcagcaaagcgttacgttatgttatttaaatctggaatgacg 152 | gagcgaagttcttatgtcggtgtgggaataattcttttgaagacagcactccttaaataa 153 | tatcgctccgtgtttgtatttatcgaatgggtctgtaaccttgcacaagcaaatcggtgg 154 | tgtatatatcggataacaattaatacgatgttcatagtgacagtatactgatcgagtcct 155 | ctaaagtcaattacctcacttaacaatctcattgatgttgtgtcattcccggtatcgccc 156 | gtagtatgtgctctgattgaccgagtgtgaaccaaggaacatctactaatgcctttgtta 157 | ggtaagatctctctgaattccttcgtgccaacttaaaacattatcaaaatttcttctact 158 | tggattaactacttttacgagcatggcaaattcccctgtggaagacggttcattattatc 159 | ggaaaccttatagaaattgcgtgttgactgaaattagatttttattgtaagagttgcatc 160 | tttgcgattcctctggtctagcttccaatgaacagtcctcccttctattcgacatcgggt 161 | ccttcgtacatgtctttgcgatgtaataattaggttcggagtgtggccttaatgggtgca 162 | actaggaatacaacgcaaatttgctgacatgatagcaaatcggtatgccggcaccaaaac 163 | gtgctccttgcttagcttgtgaatgagactcagtagttaaataaatccatatctgcaatc 164 | gattccacaggtattgtccactatctttgaactactctaagagatacaagcttagctgag 165 | accgaggtgtatatgactacgctgatatctgtaaggtaccaatgcaggcaaagtatgcga 166 | gaagctaataccggctgtttccagctttataagattaaaatttggctgtcctggcggcct 167 | cagaattgttctatcgtaatcagttggttcattaattagctaagtacgaggtacaactta 168 | tctgtcccagaacagctccacaagtttttttacagccgaaacccctgtgtgaatcttaat 169 | atccaagcgcgttatctgattagagtttacaactcagtattttatcagtacgttttgttt 170 | ccaacattacccggtatgacaaaatgacgccacgtgtcgaataatggtctgaccaatgta 171 | ggaagtgaaaagataaatat 172 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/src/revcomp-output.txt: -------------------------------------------------------------------------------- 1 | >ONE Homo sapiens alu 2 | CGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAAC 3 | CTCCGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACA 4 | GGCGCGCGCCACCACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCAT 5 | GTTGGCCAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAA 6 | AGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTC 7 | TGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCGCCTCCCGG 8 | GTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCGCGCCACC 9 | ACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGGCCAGGCTG 10 | GTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTA 11 | CAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCT 12 | GGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCGCCTCCCGGGTTCAAGCGATTC 13 | TCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCGCGCCACCACGCCCGGCTAAT 14 | TTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGGCCAGGCTGGTCTCGAACTCCT 15 | GACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCA 16 | CCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGC 17 | GCGATCTCGGCTCACTGCAACCTCCGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCC 18 | TCCCGAGTAGCTGGGATTACAGGCGCGCGCCACCACGCCCGGCTAATTTTTGTATTTTTA 19 | GTAGAGACGGGGTTTCACCATGTTGGCCAGGCTGGTCTCGAACTCCTGACCTCAGGTGAT 20 | CCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCT 21 | TTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTC 22 | ACTGCAACCTCCGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTG 23 | GGATTACAGGCGCGCGCCACCACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGT 24 | TTCACCATGTTGGCCAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGG 25 | CCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAG 26 | TCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCG 27 | CCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGC 28 | GCGCCACCACGCCCGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGG 29 | CCAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGC 30 | TGGGATTACAGGCGTGAGCCACCGCGCCCGGCCTTTTTGAGACGGAGTCTCGCTCTGTCG 31 | CCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAACCTCCGCCTCCCGGGTTCA 32 | AGCGATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCGCGCCACCACGCC 33 | CGGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTCACCATGTTGGCCAGGCTGGTCTC 34 | GAACTCCTGACCTCAGGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGC 35 | GTGAGCCACCGCGCCCGGCC 36 | >TWO IUB ambiguity codes 37 | TAGGDHACHATCRGTRGVTGAGWTATGYTGCTGTCABACDWVTRTAAGAVVAGATTTNDA 38 | GASMTCTGCATBYTTCAAKTTACMTATTACTTCATARGGYACMRTGTTTTYTATACVAAT 39 | TTCTAKGDACKADACTATATNTANTCGTTCACGBCGYSCBHTANGGTGATCGTAAAGTAA 40 | CTATBAAAAGATSTGWATBCSGAKHTTABBAACGTSYCATGCAAVATKTSKTASCGGAAT 41 | WVATTTNTCCTTCTTCTTDDAGTGGTTGGATACVGTTAYMTMTBTACTTTHAGCTAGBAA 42 | AAGAGKAAGTTRATWATCAGATTMDDTTTAAAVAAATATTKTCYTAAATTVCNKTTRACG 43 | ADTATATTTATGATSADSCAATAWAGCGRTAGTGTAAGTGACVGRADYGTGCTACHVSDT 44 | CTVCARCSYTTAATATARAAAATTTAATTTACDAATTGBACAGTAYAABATBTGCAGBVG 45 | TGATGGDCAAAATBNMSTTABKATTGGSTCCTAGBTTACTTGTTTAGTTTATHCGATSTA 46 | AAGTCGAKAAASTGTTTTAWAKCAGATATACTTTTMTTTTGBATAGAGGAGCMATGATRA 47 | AAGGNCAYDCCDDGAAAGTHGBTAATCKYTBTACBGTBCTTTTTGDTAASSWTAAWAARA 48 | TTGGCTAAGWGRADTYACATAGCTCBTAGATAWAGCAATNGTATMATGTTKMMAGTAWTC 49 | CCNTSGAAWATWCAAAAMACTGAADNTYGATNAATCCGAYWNCTAACGTTAGAGDTTTTC 50 | ATCTGGKRTAVGAABVCTGWGBTCTDVGKATTBTCTAAGGVADAAAVWTCTAGGGGAGGG 51 | TTAGAACAATTAAHTAATNAAATGCATKATCTAAYRTDTCAGSAYTTYHGATRTTWAVTA 52 | BGNTCDACAGBCCRCAGWCRTCABTGMMAWGMCTCAACCGATRTGBCAVAATCGTDWDAA 53 | CAYAWAATWCTGGTAHCCCTAAGATAACSCTTAGTGSAACAWTBGTCDTTDGACWDBAAC 54 | HTTTNGSKTYYAAYGGATNTGATTTAARTTAMBAATCTAAGTBTCATYTAACTTADTGTT 55 | TCGATACGAAHGGCYATATACCWDTKYATDCSHTDTCAAAATGTGBACTGSCCVGATGTA 56 | TCMMAGCCTTDAAABAATGAAGAGTAACTHATMGVTTAATAACCCGGTTVSANTGCAATT 57 | GTGAGATTTAMGTTTAMAAYGCTGACAYAAAAAGGCACAMYTAAGVGGCTGGAABVTACG 58 | GATTSTYGTBVAKTATWACCGTGTKAGTDTGTATGTTTAAAGGAAAAAGTAACATARAAA 59 | GGTYCAMNYAAABTATAGNTSATANAGTCATCCTATWADKAACTRGTMSACDGTATSAYT 60 | AAHSHGTAABYGACTYTATADTGSTATAGAGAAATCGNTAAAGGAAATCAGTTGTNCYMV 61 | TNACDRTATBNATATASTAGAAMSCGGGANRCKKMCAAACATTNAGTCTRMAATBMTACC 62 | CGTACTTCTBGDSYAATWGAAAATGACADDCHAKAAAYATATTKTTTTCACANACWAGAA 63 | AKATCCTTATTAYKHKCTAAACARTATTTTDATBTVWCYGCAATACTAGGKAAASTTDGA 64 | MGGCHTTHAATVCAHDRYAGGRCTATACGTCMAGAGAGCTBTHGNACARTCCBDCTAAGA 65 | GCGGCTTTARTAAAGAATCCNAGTAWBTGACTTGAATTACWTVACAGAAABCAATNAAAC 66 | CGTNTRANTTGAYCMAWBADTANABRGGTKTHTWTAGTTVCTMBKTAGMTVKCCAGCANT 67 | TVAGSWTTAGCCGCRHTTTCCTTHNTATTAAGAAGAATAGGMTRAARTCTABGTACDTTT 68 | TATAAVDHAHTATAGATCCTAGTAAGYTWATDWCATGAGGGATAGTAAMDMNGBASTWAM 69 | TSTATRBAYDABATGTATATYCGCACTGTTTTAACMCWBTATAWAGTATBTSTATVTTAR 70 | CCTMTTAAKADATCAACTAATYTSVTAKGDATTATGCKTCAYCAKAATACTTKAANGAGT 71 | ATTSDAGATCGGAAATACTTAAYAAVGTATMCGCTTGTGTDCTAATYTATTTTATTTWAA 72 | CAGWRCTATGTAGMTGTTTGTTYKTNGTTKTCAGAACNTRACCTACKTGSRATGTGGGGG 73 | CTGTCATTAAGTAAATNGSTTABCCCCTCGCAGCTCWHTCGCGAAGCAVATGCKACGHCA 74 | ACAKTTAATAACASAAADATTWNYTGTAATTGTTCGTMHACHTWATGTGCWTTTTGAAHY 75 | ACTTTGTAYAMSAAACTTAADAAATATAGTABMATATYAATGSGGTAGTTTGTGTBYGGT 76 | TWSGSVGWMATTDMTCCWWCABTCSVACAGBAATGTTKATBGTCAATAATCTTCTTAAAC 77 | ARVAATHAGYBWCTRWCABGTWWAATCTAAGTCASTAAAKTAAGVKBAATTBGABACGTA 78 | AGGTTAAATAAAAACTRMDTWBCTTTTTAATAAAAGATMGCCTACKAKNTBAGYRASTGT 79 | ASSTCGTHCGAAKTTATTATATTYTTTGTAGAACATGTCAAAACTWTWTHGKTCCYAATA 80 | AAGTGGAYTMCYTAARCSTAAATWAKTGAATTTRAGTCTSSATACGACWAKAASATDAAA 81 | TGYYACTSAACAAHAKTSHYARGASTATTATTHAGGYGGASTTTBGAKGATSANAACACD 82 | TRGSTTRAAAAAAAACAAGARTCVTAGTAAGATAWATGVHAAKATWGAAAAGTYAHVTAC 83 | TCTGRTGTCAWGATRVAAKTCGCAAVCGASWGGTTRTCSAMCCTAACASGWKKAWDAATG 84 | ACRCBACTATGTGTCTTCAAAHGSCTATATTTCGTVWAGAAGTAYCKGARAKSGKAGTAN 85 | TTTCYACATWATGTCTAAAADMDTWCAATSTKDACAMAADADBSAAATAGGCTHAHAGTA 86 | CGACVGAATTATAAAGAHCCVAYHGHTTTACATSTTTATGNCCMTAGCATATGATAVAAG 87 | >THREE Homo sapiens frequency 88 | ATATTTATCTTTTCACTTCCTACATTGGTCAGACCATTATTCGACACGTGGCGTCATTTT 89 | GTCATACCGGGTAATGTTGGAAACAAAACGTACTGATAAAATACTGAGTTGTAAACTCTA 90 | ATCAGATAACGCGCTTGGATATTAAGATTCACACAGGGGTTTCGGCTGTAAAAAAACTTG 91 | TGGAGCTGTTCTGGGACAGATAAGTTGTACCTCGTACTTAGCTAATTAATGAACCAACTG 92 | ATTACGATAGAACAATTCTGAGGCCGCCAGGACAGCCAAATTTTAATCTTATAAAGCTGG 93 | AAACAGCCGGTATTAGCTTCTCGCATACTTTGCCTGCATTGGTACCTTACAGATATCAGC 94 | GTAGTCATATACACCTCGGTCTCAGCTAAGCTTGTATCTCTTAGAGTAGTTCAAAGATAG 95 | TGGACAATACCTGTGGAATCGATTGCAGATATGGATTTATTTAACTACTGAGTCTCATTC 96 | ACAAGCTAAGCAAGGAGCACGTTTTGGTGCCGGCATACCGATTTGCTATCATGTCAGCAA 97 | ATTTGCGTTGTATTCCTAGTTGCACCCATTAAGGCCACACTCCGAACCTAATTATTACAT 98 | CGCAAAGACATGTACGAAGGACCCGATGTCGAATAGAAGGGAGGACTGTTCATTGGAAGC 99 | TAGACCAGAGGAATCGCAAAGATGCAACTCTTACAATAAAAATCTAATTTCAGTCAACAC 100 | GCAATTTCTATAAGGTTTCCGATAATAATGAACCGTCTTCCACAGGGGAATTTGCCATGC 101 | TCGTAAAAGTAGTTAATCCAAGTAGAAGAAATTTTGATAATGTTTTAAGTTGGCACGAAG 102 | GAATTCAGAGAGATCTTACCTAACAAAGGCATTAGTAGATGTTCCTTGGTTCACACTCGG 103 | TCAATCAGAGCACATACTACGGGCGATACCGGGAATGACACAACATCAATGAGATTGTTA 104 | AGTGAGGTAATTGACTTTAGAGGACTCGATCAGTATACTGTCACTATGAACATCGTATTA 105 | ATTGTTATCCGATATATACACCACCGATTTGCTTGTGCAAGGTTACAGACCCATTCGATA 106 | AATACAAACACGGAGCGATATTATTTAAGGAGTGCTGTCTTCAAAAGAATTATTCCCACA 107 | CCGACATAAGAACTTCGCTCCGTCATTCCAGATTTAAATAACATAACGTAACGCTTTGCT 108 | GATAACATAACATAACCGAGAATTTGCTTAGGAAATTTGGAGCAATATTGCATTGTTTCT 109 | CAGTCATCACAAGGCCCGCCAAAGAACTCTGAGAATCAGGATTCAACATGATTGGTAAGA 110 | CTCTATATATATAACTTAATTCTTGTGTCCGGAGATAGAAAGAGGACGAGAGATACTACG 111 | AAAGAAAGTGTACTTCGATGTATCAATTCAGACGCCTTCTCTATCATCAACATTATAGGT 112 | CTCGTATATGCTCGGCGCGATCTGCTTCTCTCCGCCAATAGCCCCATAGTGTATTTCAAG 113 | CGCAGTAACAGTGAAATCGTTACGAAGGTAGGGATGTTGCTTATAATTGTCGTAACTTAT 114 | CGCTTATGTATCTTTCAAGAATGAACGGCAGCATATACATACGTTCTACCTTTAGCTACA 115 | AAGCATCCATATACTCCCTCTCATGATTGAAACTCTTCCCTATTTTGTAGCCAATAGTGA 116 | AAGCGTATTAGTATAAATTCGTCGGTTTTTCACTCGCAACTGTTATACTCTGCAAACAAA 117 | CGAAAGCCTCATAGTACAAACCTAAAGCTACATACTTCATCATTGGCAGACCAGTGGCGG 118 | TATTTCTACGGAAGCATCACTATAGATATAAAGTTTCCCTTCATGTACGTCTGTTAACCA 119 | TATCACAAGAAACTGCTATCTCTGTCACGTAACAATTCACGCGCCTTATCGCCAAATGTT 120 | CATATATGCGCGGTATACGTATGAACGAATACTAATTAGTATAACGGAGGATTCACGGGA 121 | GGGATACTTGGGGCATTTATAAATCGTCTAAAAATTTTCTATCAGCACTTGCGGGTTATA 122 | GTGGATTACTAGGCAACATAATATTCTGTATTGGTCCAAATGACGCTATAGATAAATTAG 123 | CAAAATACATTGTTTCCATTTATGTAAGTCGAAACTCCAGGACTCCCGGGAACCAGTTAA 124 | ACCGTCTGGAAAAGACACATTGTGAGCGGGACTTCAATGATAGCTTTCAATGAGCTTCTC 125 | ATGCTTGGGGTCTGTACATATATGTTGGCGAAATTATCGTCTGTATTCTGTTATGCTTTG 126 | ATCATGGGTTATTAGTATAGTGTCCGGTTAAGTACCAATACCGCTAGAGACCCGACCTAA 127 | GTCGATAACTAACGATCATCGACGTAAGGATCGTCTCGATCAGTACTTCAGTCTAGATCT 128 | GGGAATAGTAACTCGTTAGTGAACTATGTCGTGTCATAACTCTAAAATGCAATCAAATCT 129 | TATTATTGAGTATTGATTATATAAAGCATCCGCTTAGCTTTACCCTCAAATGTTATATGC 130 | AATTTAAAGCGCTTGATATCGTCTACTCAAGTTCAGGTTTCACATGGCCGCAACGTGACG 131 | TTATTAGAGGTGGGTCATCATCTCTGAGGCTAGTGATGTTGAATACTCATTGAATGGGAA 132 | GTGGAATACCATGCTCGTAGGTAACAGCATGACCTATAAAATATACTATGGGTGTGTGGT 133 | AGATCAATATTGTTCAAGCATATCGTAACAATAACGGCTGAAATGTTACTGACATGAAAG 134 | AGGGAGTCCAAACCATTCTAACAGCTGATCAAGTCGTCTAAAAACGCCTGGTTCAGCCTT 135 | AAGAGTTATAAGCCAGACAAATTGTATCAATAGAGAATCCGTAAATTCCTCGGCCAACCT 136 | CTTGCAAAGACATCACTATCAATATACTACCGTGATCTTAATTAGTGAACTTATATAAAT 137 | ATCTACAACCAGATTCAACGGAAAAGCTTTAGTGGATTAGAAATTGCCAAGAATCACATT 138 | CATGTGGGTTCGAATGCTTTAGTAATACCATTTCGCCGAGTAGTCACTTCGCTGAACTGT 139 | CGTAAATTGCTATGACATAATCGAAAAGGATTGTCAAGAGTCGATTACTGCGGACTAATA 140 | ATCCCCACGGGGGTGGTCTCATGTCTCCCCAGGCGAGTGGGGACGGTTGATAAACACGCT 141 | GCATCGCGGACTGATGTTCCCAGTATTACATAGTCACATTGGATTGCGAGTAGTCTACCT 142 | ATTTATGAGCGAGAGATGCCTCTAACTACTTCGACTTTTAAAACCTTTCCACGCCAGTAT 143 | TCGGCGAAAGGGAAGTATTAAGGGTTGTCATAATTAAGCTGATACCACTTCAGACTTTGC 144 | TCTACTTCTGTCTTTCATTGGTTTAGTAAAGTCTGTCCATTCGTCGAGACCGTCTTTTGC 145 | AGCCTCATTCTACCAACTGCTCCGACTCTTAGTCTGCTTCTCCCAGCGTTATAACAAGAG 146 | GCATTTTGTCATCCTTAAAACAATAATAAAGAACTCGGAGCACTGATATAATGACTGAAT 147 | TAGAACCGCTTAAAAATACAACGAATAGATAAGACTATCGGATAAGATCTAATATGTAGT 148 | GATTAAGCCCTTTATTAATTAATAATAGTTACCCTTTCTGATGTAACGCGACATATTACG 149 | ATTTAGTGGCACGTCTGAATTGCAAAGCAGATCTCTACCCGATTTTTATTATAAATCCCG 150 | TATACATCTTGACTTGAGTAATTGTTCATCTTTTTATATCTCTTCGTACTACAAATAATT 151 | AATATCTCAACCCGTATTGTGTGATTCTAATTACCAACAGAATACGAGGAGGTTTTTGCT 152 | TAGGGCCATATATAATGAATCTATCTCGTTTATTCGCGGAACCCGAGATAACATTACGAT 153 | GTAACTATTTTAGAGAACTTAATACAAGAAACATTGCTGATTACTCATAACTAAATGCTT 154 | GGTAATATATCCTCAGTGCCCCTACCATCTTTTACGCAGGGATGTAATTACTTAGGATTC 155 | ATTGTGTAAGAATTACAATGAACGATGGATATGAAGGCATGTTGCGAGGTGTTCCTTGGT 156 | ATGTGAAGTTCGCAGGGCAACAAAAATTTCGCAGAATAGGCCTCAAAGTATTGGTAAAGA 157 | AGACAACTAATCATCACGAGCTTCTGATATCAATACGAACGAGTCCTGTGATGGATGAAA 158 | GAAAGTCGTATCGAAAATGTCAAGAGTCTGCCCAATGTAACTTACTTCAAAAAATAACGC 159 | TTCCGCCAAGTACGTTCGAATAAACGTAATTTTAAAAATACATAAGGGGTGTTAGAAAGT 160 | AAGCGACGGGATATAAGTTAGACTCAAGATTCCGCCGTAAAACGAGACTGATTCCGAAGA 161 | TTGTTCGTGGATCTGGTCATGACTTTCACTGAGTAAGGAGTTTCGACATATGTCAATAAA 162 | CACAAAAATAGAAGCTATTCGATCTGAAAAATATTAGGACAAGAAACTATCTCACGCTAG 163 | CCCAGAATATTCACTCACCCACGGGCGATACTAAAGCACTATATAGTCGCGTGATTACTA 164 | TACATATGGTACACATAAGAATCACGATCAGGTTCTCAATTTTCAACAATATATGTTTAT 165 | TTGCATAGGTAATATTAGGCCTTTAAGAGAAGGATGGGTGAGATACTCCGGGGATGGCGG 166 | CAATAAAGAAAAACACGATATGAGTAATAGGATCCTAATATCTTGGCGAGAGACTTAAGG 167 | TACGAATTTTGCGCAATCTATTTTTTACTTGGCCAGAATTCATGTATGGTATAAGTACGA 168 | ACTTTTTTGATCACTTTCATGGCTACCTGATTAGGATAGTTTGAGGAATTTCCCAAATAT 169 | ACCGATTTAATATACACTAGGGCTTGTCACTTTGAGTCAGAAAAAGAATATAATTACTTA 170 | GGGTAATGCTGCATACATATTCTTATATTGCAAAGGTTCTCTGGGTAATCTTGAGCCTTC 171 | ACGATACCTGGTGAAGTGTT 172 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/wasm-kernel/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/wasm-kernel/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-kernel" 3 | version = "0.1.0" 4 | authors = ["Sergey Pepyakin "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | tiny-keccak = "1.4.2" 11 | regex = "0.2.10" 12 | lazy_static = "1.0" 13 | 14 | [profile.release] 15 | panic = "abort" 16 | lto = true 17 | opt-level = "z" 18 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/wasm-kernel/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate tiny_keccak; 2 | extern crate regex; 3 | #[macro_use] 4 | extern crate lazy_static; 5 | 6 | use std::mem::ManuallyDrop; 7 | use tiny_keccak::Keccak; 8 | 9 | mod rev_complement; 10 | mod regex_redux; 11 | 12 | pub struct TinyKeccakTestData { 13 | data: &'static [u8], 14 | result: &'static mut [u8], 15 | } 16 | 17 | #[no_mangle] 18 | pub extern "C" fn prepare_tiny_keccak() -> *const TinyKeccakTestData { 19 | static DATA: [u8; 4096] = [254u8; 4096]; 20 | static mut RESULT: [u8; 32] = [0u8; 32]; 21 | 22 | static mut TEST_DATA: Option = None; 23 | 24 | unsafe { 25 | if let None = TEST_DATA { 26 | TEST_DATA = Some(TinyKeccakTestData { 27 | data: &DATA, 28 | result: &mut RESULT, 29 | }); 30 | } 31 | TEST_DATA.as_ref().unwrap() as *const TinyKeccakTestData 32 | } 33 | } 34 | 35 | #[no_mangle] 36 | pub extern "C" fn bench_tiny_keccak(test_data: *const TinyKeccakTestData) { 37 | unsafe { 38 | let mut keccak = Keccak::new_keccak256(); 39 | keccak.update((*test_data).data); 40 | keccak.finalize((*test_data).result); 41 | } 42 | } 43 | 44 | pub struct RevComplementTestData { 45 | input: ManuallyDrop>, 46 | output: ManuallyDrop>, 47 | } 48 | 49 | #[no_mangle] 50 | pub extern "C" fn prepare_rev_complement(size: usize) -> *mut RevComplementTestData { 51 | let input = vec![0; size]; 52 | let output = vec![0; size]; 53 | 54 | let test_data = Box::new( 55 | RevComplementTestData { 56 | input: ManuallyDrop::new(input.into_boxed_slice()), 57 | output: ManuallyDrop::new(output.into_boxed_slice()), 58 | } 59 | ); 60 | 61 | // Basically leak the pointer to the test data. This shouldn't be harmful since `prepare` is called 62 | // only once per bench run (not for the iteration), and afterwards whole memory instance is discarded. 63 | Box::into_raw(test_data) 64 | } 65 | 66 | #[no_mangle] 67 | pub extern "C" fn rev_complement_input_ptr(test_data: *mut RevComplementTestData) -> *mut u8 { 68 | unsafe { 69 | (*test_data).input.as_mut_ptr() 70 | } 71 | } 72 | 73 | #[no_mangle] 74 | pub extern "C" fn rev_complement_output_ptr(test_data: *mut RevComplementTestData) -> *const u8 { 75 | unsafe { 76 | (*test_data).output.as_ptr() 77 | } 78 | } 79 | 80 | #[no_mangle] 81 | pub extern "C" fn bench_rev_complement(test_data: *mut RevComplementTestData) { 82 | unsafe { 83 | let result = rev_complement::run(&*(*test_data).input); 84 | (*test_data).output.copy_from_slice(&result); 85 | } 86 | } 87 | 88 | pub struct RegexReduxTestData { 89 | input: ManuallyDrop>, 90 | output: Option, 91 | } 92 | 93 | #[no_mangle] 94 | pub extern "C" fn prepare_regex_redux(size: usize) -> *mut RegexReduxTestData { 95 | regex_redux::prepare(); 96 | 97 | let input = vec![0; size]; 98 | let test_data = Box::new( 99 | RegexReduxTestData { 100 | input: ManuallyDrop::new(input.into_boxed_slice()), 101 | output: None, 102 | } 103 | ); 104 | 105 | // Basically leak the pointer to the test data. This shouldn't be harmful since `prepare` is called 106 | // only once per bench run (not for the iteration), and afterwards whole memory instance is discarded. 107 | Box::into_raw(test_data) 108 | } 109 | 110 | #[no_mangle] 111 | pub extern "C" fn regex_redux_input_ptr(test_data: *mut RegexReduxTestData) -> *mut u8 { 112 | unsafe { 113 | (*test_data).input.as_mut_ptr() 114 | } 115 | } 116 | 117 | #[no_mangle] 118 | pub extern "C" fn bench_regex_redux(test_data: *mut RegexReduxTestData) { 119 | unsafe { 120 | let result = regex_redux::run(&*(*test_data).input); 121 | (*test_data).output = Some(result); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/wasm-kernel/src/regex_redux.rs: -------------------------------------------------------------------------------- 1 | //! Initially it supposed to be like [1]. However it turned out 2 | //! that executing this code in wasmi way too slow. 3 | //! 4 | //! [1]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/regexredux-rust-2.html 5 | 6 | lazy_static! { 7 | static ref REGEX: ::regex::bytes::Regex = 8 | { ::regex::bytes::Regex::new("agggtaa[cgt]|[acg]ttaccct").unwrap() }; 9 | } 10 | 11 | pub fn prepare() { 12 | ::lazy_static::initialize(®EX); 13 | } 14 | 15 | pub fn run(seq: &[u8]) -> usize { 16 | REGEX.find_iter(seq).count() 17 | } 18 | -------------------------------------------------------------------------------- /vendor/wasmi/benches/wasm-kernel/src/rev_complement.rs: -------------------------------------------------------------------------------- 1 | // Adapted version from benchmarks game. In particular 2 | // rayon is removed. 3 | // 4 | // https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/revcomp-rust-3.html 5 | 6 | // The Computer Language Benchmarks Game 7 | // https://salsa.debian.org/benchmarksgame-team/benchmarksgame/ 8 | // 9 | // contributed by the Rust Project Developers 10 | // contributed by Cristi Cobzarenco 11 | // contributed by TeXitoi 12 | // contributed by Matt Brubeck 13 | 14 | use std::io::BufRead; 15 | use std::mem::replace; 16 | use std::{cmp, io}; 17 | 18 | /// Lookup table to find the complement of a single FASTA code. 19 | fn build_table() -> [u8; 256] { 20 | let mut table = [0; 256]; 21 | for (i, x) in table.iter_mut().enumerate() { 22 | *x = match i as u8 as char { 23 | 'A' | 'a' => 'T', 24 | 'C' | 'c' => 'G', 25 | 'G' | 'g' => 'C', 26 | 'T' | 't' => 'A', 27 | 'U' | 'u' => 'A', 28 | 'M' | 'm' => 'K', 29 | 'R' | 'r' => 'Y', 30 | 'W' | 'w' => 'W', 31 | 'S' | 's' => 'S', 32 | 'Y' | 'y' => 'R', 33 | 'K' | 'k' => 'M', 34 | 'V' | 'v' => 'B', 35 | 'H' | 'h' => 'D', 36 | 'D' | 'd' => 'H', 37 | 'B' | 'b' => 'V', 38 | 'N' | 'n' => 'N', 39 | i => i, 40 | } as u8; 41 | } 42 | table 43 | } 44 | 45 | /// Utilities for splitting chunks off of slices. 46 | trait SplitOff { 47 | fn split_off_left(&mut self, n: usize) -> Self; 48 | fn split_off_right(&mut self, n: usize) -> Self; 49 | } 50 | impl<'a, T> SplitOff for &'a mut [T] { 51 | /// Split the left `n` items from self and return them as a separate slice. 52 | fn split_off_left(&mut self, n: usize) -> Self { 53 | let n = cmp::min(self.len(), n); 54 | let data = replace(self, &mut []); 55 | let (left, data) = data.split_at_mut(n); 56 | *self = data; 57 | left 58 | } 59 | /// Split the right `n` items from self and return them as a separate slice. 60 | fn split_off_right(&mut self, n: usize) -> Self { 61 | let len = self.len(); 62 | let n = cmp::min(len, n); 63 | let data = replace(self, &mut []); 64 | let (data, right) = data.split_at_mut(len - n); 65 | *self = data; 66 | right 67 | } 68 | } 69 | 70 | /// Length of a normal line including the terminating \n. 71 | const LINE_LEN: usize = 61; 72 | 73 | /// Compute the reverse complement for two contiguous chunks without line breaks. 74 | fn reverse_chunks(left: &mut [u8], right: &mut [u8], table: &[u8; 256]) { 75 | for (x, y) in left.iter_mut().zip(right.iter_mut().rev()) { 76 | *y = table[replace(x, table[*y as usize]) as usize]; 77 | } 78 | } 79 | 80 | /// Compute the reverse complement on chunks from opposite ends of a sequence. 81 | /// 82 | /// `left` must start at the beginning of a line. If there are an odd number of 83 | /// bytes, `right` will initially be 1 byte longer than `left`; otherwise they 84 | /// will have equal lengths. 85 | fn reverse_complement_left_right( 86 | mut left: &mut [u8], 87 | mut right: &mut [u8], 88 | trailing_len: usize, 89 | table: &[u8; 256], 90 | ) { 91 | // Each iteration swaps one line from the start of the sequence with one 92 | // from the end. 93 | while left.len() > 0 || right.len() > 0 { 94 | // Get the chunk up to the newline in `right`. 95 | let mut a = left.split_off_left(trailing_len); 96 | let mut b = right.split_off_right(trailing_len); 97 | right.split_off_right(1); // Skip the newline in `right`. 98 | 99 | // If we've reached the middle of the sequence here and there is an 100 | // odd number of bytes remaining, the odd one will be on the right. 101 | if b.len() > a.len() { 102 | let mid = b.split_off_left(1); 103 | mid[0] = table[mid[0] as usize]; 104 | } 105 | 106 | reverse_chunks(a, b, table); 107 | 108 | // Get the chunk up to the newline in `left`. 109 | let n = LINE_LEN - 1 - trailing_len; 110 | a = left.split_off_left(n); 111 | b = right.split_off_right(n); 112 | left.split_off_left(1); // Skip the newline in `left`. 113 | 114 | // If we've reached the middle of the sequence and there is an odd 115 | // number of bytes remaining, the odd one will now be on the left. 116 | if a.len() > b.len() { 117 | let mid = a.split_off_right(1); 118 | mid[0] = table[mid[0] as usize] 119 | } 120 | 121 | reverse_chunks(a, b, table); 122 | } 123 | } 124 | 125 | /// Compute the reverse complement of one sequence. 126 | fn reverse_complement(seq: &mut [u8], table: &[u8; 256]) { 127 | let len = seq.len() - 1; 128 | let seq = &mut seq[..len]; // Drop the last newline 129 | let trailing_len = len % LINE_LEN; 130 | let (left, right) = seq.split_at_mut(len / 2); 131 | reverse_complement_left_right(left, right, trailing_len, table); 132 | } 133 | 134 | /// Read sequences from stdin and print the reverse complement to stdout. 135 | pub fn run(input: &[u8]) -> Vec { 136 | let mut buf = Vec::with_capacity(input.len()); 137 | 138 | let mut input = io::Cursor::new(input); 139 | 140 | // Read the first header line. 141 | input.read_until(b'\n', &mut buf).unwrap(); 142 | 143 | // Read sequence data line-by-line, splitting on headers. 144 | let mut line_start = buf.len(); 145 | let mut seq_start = line_start; 146 | let mut seqs = vec![]; 147 | while input.read_until(b'\n', &mut buf).unwrap() > 0 { 148 | if buf[line_start] == b'>' { 149 | // Found the start of a new sequence. 150 | seqs.push(seq_start..line_start); 151 | seq_start = buf.len(); 152 | } 153 | line_start = buf.len(); 154 | } 155 | seqs.push(seq_start..buf.len()); 156 | 157 | // Compute the reverse complements of each sequence. 158 | let table = build_table(); 159 | for seq in seqs { 160 | reverse_complement(&mut buf[seq], &table); 161 | } 162 | 163 | buf 164 | } 165 | -------------------------------------------------------------------------------- /vendor/wasmi/check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | cd $(dirname $0) 6 | 7 | cargo check --tests 8 | 9 | cd - 10 | -------------------------------------------------------------------------------- /vendor/wasmi/doc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | cd $(dirname $0) 6 | 7 | cargo doc 8 | 9 | # cargo-deadlinks will check any links in docs generated by `cargo doc`. 10 | # This is useful as rustdoc uses raw links which are error prone. 11 | command -v cargo-deadlinks &> /dev/null && 12 | cargo deadlinks 13 | 14 | cd - 15 | -------------------------------------------------------------------------------- /vendor/wasmi/examples/interpret.rs: -------------------------------------------------------------------------------- 1 | // In this example we execute a contract funciton exported as "_call" 2 | 3 | extern crate wasmi; 4 | 5 | use std::env::args; 6 | use std::fs::File; 7 | use wasmi::{ImportsBuilder, Module, ModuleInstance, NopExternals, RuntimeValue}; 8 | 9 | fn load_from_file(filename: &str) -> Module { 10 | use std::io::prelude::*; 11 | let mut file = File::open(filename).unwrap(); 12 | let mut buf = Vec::new(); 13 | file.read_to_end(&mut buf).unwrap(); 14 | Module::from_buffer(buf).unwrap() 15 | } 16 | 17 | fn main() { 18 | let args: Vec<_> = args().collect(); 19 | if args.len() != 3 { 20 | println!("Usage: {} ", args[0]); 21 | println!(" wasm file should contain exported `_call` function with single I32 argument"); 22 | return; 23 | } 24 | 25 | // Here we load module using dedicated for this purpose 26 | // `load_from_file` function (which works only with modules) 27 | let module = load_from_file(&args[1]); 28 | 29 | // Intialize deserialized module. It adds module into It expects 3 parameters: 30 | // - a name for the module 31 | // - a module declaration 32 | // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here 33 | // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 34 | let main = ModuleInstance::new(&module, &ImportsBuilder::default()) 35 | .expect("Failed to instantiate module") 36 | .run_start(&mut NopExternals) 37 | .expect("Failed to run start function in module"); 38 | 39 | // The argument should be parsable as a valid integer 40 | let argument: i32 = args[2].parse().expect("Integer argument required"); 41 | 42 | // "_call" export of function to be executed with an i32 argument and prints the result of execution 43 | println!( 44 | "Result: {:?}", 45 | main.invoke_export("_call", &[RuntimeValue::I32(argument)], &mut NopExternals) 46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /vendor/wasmi/examples/invoke.rs: -------------------------------------------------------------------------------- 1 | extern crate parity_wasm; 2 | extern crate wasmi; 3 | 4 | use std::env::args; 5 | 6 | use parity_wasm::elements::{External, FunctionType, Internal, Type, ValueType}; 7 | use wasmi::{ImportsBuilder, ModuleInstance, NopExternals, RuntimeValue}; 8 | 9 | fn main() { 10 | let args: Vec<_> = args().collect(); 11 | if args.len() < 3 { 12 | println!("Usage: {} [...]", args[0]); 13 | return; 14 | } 15 | let func_name = &args[2]; 16 | let (_, program_args) = args.split_at(3); 17 | 18 | let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized"); 19 | 20 | // Extracts call arguments from command-line arguments 21 | let args = { 22 | // Export section has an entry with a func_name with an index inside a module 23 | let export_section = module.export_section().expect("No export section found"); 24 | // It's a section with function declarations (which are references to the type section entries) 25 | let function_section = module 26 | .function_section() 27 | .expect("No function section found"); 28 | // Type section stores function types which are referenced by function_section entries 29 | let type_section = module.type_section().expect("No type section found"); 30 | 31 | // Given function name used to find export section entry which contains 32 | // an `internal` field which points to the index in the function index space 33 | let found_entry = export_section 34 | .entries() 35 | .iter() 36 | .find(|entry| func_name == entry.field()) 37 | .expect(&format!("No export with name {} found", func_name)); 38 | 39 | // Function index in the function index space (internally-defined + imported) 40 | let function_index: usize = match found_entry.internal() { 41 | &Internal::Function(index) => index as usize, 42 | _ => panic!("Founded export is not a function"), 43 | }; 44 | 45 | // We need to count import section entries (functions only!) to subtract it from function_index 46 | // and obtain the index within the function section 47 | let import_section_len: usize = match module.import_section() { 48 | Some(import) => import 49 | .entries() 50 | .iter() 51 | .filter(|entry| match entry.external() { 52 | &External::Function(_) => true, 53 | _ => false, 54 | }) 55 | .count(), 56 | None => 0, 57 | }; 58 | 59 | // Calculates a function index within module's function section 60 | let function_index_in_section = function_index - import_section_len; 61 | 62 | // Getting a type reference from a function section entry 63 | let func_type_ref: usize = 64 | function_section.entries()[function_index_in_section].type_ref() as usize; 65 | 66 | // Use the reference to get an actual function type 67 | let function_type: &FunctionType = match &type_section.types()[func_type_ref] { 68 | &Type::Function(ref func_type) => func_type, 69 | }; 70 | 71 | // Parses arguments and constructs runtime values in correspondence of their types 72 | function_type 73 | .params() 74 | .iter() 75 | .enumerate() 76 | .map(|(i, value)| match value { 77 | &ValueType::I32 => RuntimeValue::I32( 78 | program_args[i] 79 | .parse::() 80 | .expect(&format!("Can't parse arg #{} as i32", program_args[i])), 81 | ), 82 | &ValueType::I64 => RuntimeValue::I64( 83 | program_args[i] 84 | .parse::() 85 | .expect(&format!("Can't parse arg #{} as i64", program_args[i])), 86 | ), 87 | &ValueType::F32 => RuntimeValue::F32( 88 | program_args[i] 89 | .parse::() 90 | .expect(&format!("Can't parse arg #{} as f32", program_args[i])) 91 | .into(), 92 | ), 93 | &ValueType::F64 => RuntimeValue::F64( 94 | program_args[i] 95 | .parse::() 96 | .expect(&format!("Can't parse arg #{} as f64", program_args[i])) 97 | .into(), 98 | ), 99 | }) 100 | .collect::>() 101 | }; 102 | 103 | let loaded_module = wasmi::Module::from_parity_wasm_module(module).expect("Module to be valid"); 104 | 105 | // Intialize deserialized module. It adds module into It expects 3 parameters: 106 | // - a name for the module 107 | // - a module declaration 108 | // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here 109 | // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 110 | let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default()) 111 | .expect("Failed to instantiate module") 112 | .run_start(&mut NopExternals) 113 | .expect("Failed to run start function in module"); 114 | 115 | println!( 116 | "Result: {:?}", 117 | main.invoke_export(func_name, &args, &mut NopExternals) 118 | .expect("") 119 | ); 120 | } 121 | -------------------------------------------------------------------------------- /vendor/wasmi/examples/tictactoe.rs: -------------------------------------------------------------------------------- 1 | extern crate parity_wasm; 2 | extern crate wasmi; 3 | 4 | use std::env; 5 | use std::fmt; 6 | use std::fs::File; 7 | use wasmi::{ 8 | Error as InterpreterError, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, 9 | ModuleImportResolver, ModuleInstance, ModuleRef, RuntimeArgs, RuntimeValue, Signature, Trap, 10 | ValueType, 11 | }; 12 | 13 | #[derive(Debug)] 14 | pub enum Error { 15 | OutOfRange, 16 | AlreadyOccupied, 17 | Interpreter(InterpreterError), 18 | } 19 | 20 | impl fmt::Display for Error { 21 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 22 | write!(f, "{:?}", self) 23 | } 24 | } 25 | 26 | impl From for Error { 27 | fn from(e: InterpreterError) -> Self { 28 | Error::Interpreter(e) 29 | } 30 | } 31 | 32 | impl HostError for Error {} 33 | 34 | mod tictactoe { 35 | use super::Error; 36 | 37 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 38 | pub enum Player { 39 | X, 40 | O, 41 | } 42 | 43 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 44 | pub enum GameResult { 45 | Draw, 46 | Won(Player), 47 | } 48 | 49 | impl Player { 50 | pub fn into_i32(maybe_player: Option) -> i32 { 51 | match maybe_player { 52 | None => 0, 53 | Some(Player::X) => 1, 54 | Some(Player::O) => 2, 55 | } 56 | } 57 | } 58 | 59 | #[derive(Debug)] 60 | pub struct Game { 61 | board: [Option; 9], 62 | } 63 | 64 | impl Game { 65 | pub fn new() -> Game { 66 | Game { board: [None; 9] } 67 | } 68 | 69 | pub fn set(&mut self, idx: i32, player: Player) -> Result<(), Error> { 70 | if idx < 0 || idx > 9 { 71 | return Err(Error::OutOfRange); 72 | } 73 | if self.board[idx as usize] != None { 74 | return Err(Error::AlreadyOccupied); 75 | } 76 | self.board[idx as usize] = Some(player); 77 | Ok(()) 78 | } 79 | 80 | pub fn get(&self, idx: i32) -> Result, Error> { 81 | if idx < 0 || idx > 9 { 82 | return Err(Error::OutOfRange); 83 | } 84 | Ok(self.board[idx as usize]) 85 | } 86 | 87 | pub fn game_result(&self) -> Option { 88 | // 0, 1, 2 89 | // 3, 4, 5 90 | // 6, 7, 8 91 | let patterns = &[ 92 | // Rows 93 | (0, 1, 2), 94 | (3, 4, 5), 95 | (6, 7, 8), 96 | // Columns 97 | (0, 3, 6), 98 | (1, 4, 7), 99 | (2, 5, 8), 100 | // Diagonals 101 | (0, 4, 8), 102 | (2, 4, 6), 103 | ]; 104 | 105 | // Returns Some(player) if all cells contain same Player. 106 | let all_same = |i1: usize, i2: usize, i3: usize| -> Option { 107 | if self.board[i1].is_none() { 108 | return None; 109 | } 110 | if self.board[i1] == self.board[i2] && self.board[i2] == self.board[i3] { 111 | return self.board[i1]; 112 | } 113 | None 114 | }; 115 | 116 | for &(i1, i2, i3) in patterns { 117 | if let Some(player) = all_same(i1, i2, i3) { 118 | return Some(GameResult::Won(player)); 119 | } 120 | } 121 | 122 | // Ok, there is no winner. Check if it's draw. 123 | let all_occupied = self.board.iter().all(|&cell| cell.is_some()); 124 | if all_occupied { 125 | Some(GameResult::Draw) 126 | } else { 127 | // Nah, there are still empty cells left. 128 | None 129 | } 130 | } 131 | } 132 | } 133 | 134 | struct Runtime<'a> { 135 | player: tictactoe::Player, 136 | game: &'a mut tictactoe::Game, 137 | } 138 | 139 | const SET_FUNC_INDEX: usize = 0; 140 | const GET_FUNC_INDEX: usize = 1; 141 | 142 | impl<'a> Externals for Runtime<'a> { 143 | fn invoke_index( 144 | &mut self, 145 | index: usize, 146 | args: RuntimeArgs, 147 | ) -> Result, Trap> { 148 | match index { 149 | SET_FUNC_INDEX => { 150 | let idx: i32 = args.nth(0); 151 | self.game.set(idx, self.player)?; 152 | Ok(None) 153 | } 154 | GET_FUNC_INDEX => { 155 | let idx: i32 = args.nth(0); 156 | let val: i32 = tictactoe::Player::into_i32(self.game.get(idx)?); 157 | Ok(Some(val.into())) 158 | } 159 | _ => panic!("unknown function index"), 160 | } 161 | } 162 | } 163 | 164 | struct RuntimeModuleImportResolver; 165 | 166 | impl<'a> ModuleImportResolver for RuntimeModuleImportResolver { 167 | fn resolve_func( 168 | &self, 169 | field_name: &str, 170 | _signature: &Signature, 171 | ) -> Result { 172 | let func_ref = match field_name { 173 | "set" => FuncInstance::alloc_host( 174 | Signature::new(&[ValueType::I32][..], None), 175 | SET_FUNC_INDEX, 176 | ), 177 | "get" => FuncInstance::alloc_host( 178 | Signature::new(&[ValueType::I32][..], Some(ValueType::I32)), 179 | GET_FUNC_INDEX, 180 | ), 181 | _ => { 182 | return Err(InterpreterError::Function(format!( 183 | "host module doesn't export function with name {}", 184 | field_name 185 | ))); 186 | } 187 | }; 188 | Ok(func_ref) 189 | } 190 | } 191 | 192 | fn instantiate(path: &str) -> Result { 193 | let module = { 194 | use std::io::prelude::*; 195 | let mut file = File::open(path).unwrap(); 196 | let mut wasm_buf = Vec::new(); 197 | file.read_to_end(&mut wasm_buf).unwrap(); 198 | wasmi::Module::from_buffer(&wasm_buf)? 199 | }; 200 | 201 | let mut imports = ImportsBuilder::new(); 202 | imports.push_resolver("env", &RuntimeModuleImportResolver); 203 | 204 | let instance = ModuleInstance::new(&module, &imports)?.assert_no_start(); 205 | 206 | Ok(instance) 207 | } 208 | 209 | fn play( 210 | x_instance: ModuleRef, 211 | o_instance: ModuleRef, 212 | game: &mut tictactoe::Game, 213 | ) -> Result { 214 | let mut turn_of = tictactoe::Player::X; 215 | let game_result = loop { 216 | let (instance, next_turn_of) = match turn_of { 217 | tictactoe::Player::X => (&x_instance, tictactoe::Player::O), 218 | tictactoe::Player::O => (&o_instance, tictactoe::Player::X), 219 | }; 220 | 221 | { 222 | let mut runtime = Runtime { 223 | player: turn_of, 224 | game: game, 225 | }; 226 | let _ = instance.invoke_export("mk_turn", &[], &mut runtime)?; 227 | } 228 | 229 | match game.game_result() { 230 | Some(game_result) => break game_result, 231 | None => {} 232 | } 233 | 234 | turn_of = next_turn_of; 235 | }; 236 | 237 | Ok(game_result) 238 | } 239 | 240 | fn main() { 241 | let mut game = tictactoe::Game::new(); 242 | 243 | let args: Vec<_> = env::args().collect(); 244 | if args.len() < 3 { 245 | println!("Usage: {} ", args[0]); 246 | return; 247 | } 248 | 249 | // Instantiate modules of X and O players. 250 | let x_instance = instantiate(&args[1]).expect("X player module to load"); 251 | let o_instance = instantiate(&args[2]).expect("Y player module to load"); 252 | 253 | let result = play(x_instance, o_instance, &mut game); 254 | println!("result = {:?}, game = {:#?}", result, game); 255 | } 256 | -------------------------------------------------------------------------------- /vendor/wasmi/fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | target 3 | corpus 4 | artifacts 5 | -------------------------------------------------------------------------------- /vendor/wasmi/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "wasmi-fuzz" 4 | version = "0.0.1" 5 | authors = ["Automatically generated"] 6 | publish = false 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [dependencies] 12 | wasmi = { path = ".." } 13 | wabt = "0.6.0" 14 | wasmparser = "0.14.1" 15 | tempdir = "0.3.6" 16 | 17 | [dependencies.libfuzzer-sys] 18 | git = "https://github.com/rust-fuzz/libfuzzer-sys.git" 19 | rev = "737524f7de1e85342b8b6cd1c01edc71018183ba" 20 | 21 | # Prevent this from interfering with workspaces 22 | [workspace] 23 | members = ["."] 24 | 25 | [[bin]] 26 | name = "load" 27 | path = "fuzz_targets/load.rs" 28 | 29 | [[bin]] 30 | name = "load_wabt" 31 | path = "fuzz_targets/load_wabt.rs" 32 | 33 | [[bin]] 34 | name = "load_wasmparser" 35 | path = "fuzz_targets/load_wasmparser.rs" 36 | 37 | [[bin]] 38 | name = "load_spec" 39 | path = "fuzz_targets/load_spec.rs" 40 | -------------------------------------------------------------------------------- /vendor/wasmi/fuzz/fuzz_targets/load.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate wasmi; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | // Just check if loading some arbitrary buffer doesn't panic. 8 | let _ = wasmi::Module::from_buffer(data); 9 | }); 10 | -------------------------------------------------------------------------------- /vendor/wasmi/fuzz/fuzz_targets/load_spec.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate wabt; 5 | extern crate wasmi; 6 | extern crate tempdir; 7 | 8 | use std::fs::File; 9 | use std::io::Write; 10 | use std::process::{Command, Stdio}; 11 | 12 | fn run_spec(data: &[u8]) -> Result<(), ()> { 13 | let temp_dir = tempdir::TempDir::new("spec").unwrap(); 14 | let mut seed_path = temp_dir.path().to_path_buf(); 15 | seed_path.push("test.wasm"); 16 | 17 | { 18 | let mut seedfile = 19 | File::create(&seed_path).expect("open temporary file for writing to store fuzzer input"); 20 | seedfile.write_all(data).expect( 21 | "write fuzzer input to temporary file", 22 | ); 23 | seedfile.flush().expect( 24 | "flush fuzzer input to temporary file before starting wasm-opt", 25 | ); 26 | } 27 | 28 | let exit_status = Command::new("wasm") 29 | .arg("-d") 30 | .arg(&seed_path) 31 | .stdout(Stdio::null()) 32 | .stderr(Stdio::null()) 33 | .status() 34 | .expect("failed to execute `wasm`"); 35 | 36 | if exit_status.success() { 37 | Ok(()) 38 | } else { 39 | Err(()) 40 | } 41 | } 42 | 43 | fn run_wasmi(data: &[u8]) -> Result<(), ()> { 44 | let _ = wasmi::Module::from_buffer(data).map_err(|_| ())?; 45 | Ok(()) 46 | } 47 | 48 | fuzz_target!(|data: &[u8]| { 49 | let wasmi_result = run_wasmi(data); 50 | let wasm_result = run_spec(data); 51 | 52 | assert_eq!(wasmi_result.is_ok(), wasm_result.is_ok()); 53 | }); 54 | -------------------------------------------------------------------------------- /vendor/wasmi/fuzz/fuzz_targets/load_wabt.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate wabt; 5 | extern crate wasmi; 6 | 7 | fuzz_target!(|data: &[u8]| { 8 | let wasmi_result = wasmi::Module::from_buffer(data); 9 | let wabt_result = 10 | wabt::Module::read_binary(data, &Default::default()).and_then(|m| m.validate()); 11 | 12 | assert_eq!(wasmi_result.is_ok(), wabt_result.is_ok()); 13 | }); 14 | -------------------------------------------------------------------------------- /vendor/wasmi/fuzz/fuzz_targets/load_wasmparser.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate wasmi; 5 | extern crate wasmparser; 6 | 7 | use wasmparser::WasmDecoder; 8 | 9 | fn run_wasmparser(data: &[u8]) -> bool { 10 | let mut parser = wasmparser::ValidatingParser::new(data, None); 11 | let result = loop { 12 | match *parser.read() { 13 | wasmparser::ParserState::Error(..) => break false, 14 | wasmparser::ParserState::EndWasm => break true, 15 | _ => (), 16 | } 17 | }; 18 | result 19 | } 20 | 21 | fn run_wasmi(data: &[u8]) -> bool { 22 | wasmi::Module::from_buffer(data).is_ok() 23 | } 24 | 25 | fuzz_target!(|data: &[u8]| { 26 | let wasmparser_success = run_wasmparser(data); 27 | let wasmi_success = run_wasmi(data); 28 | assert_eq!(wasmparser_success, wasmi_success); 29 | }); 30 | -------------------------------------------------------------------------------- /vendor/wasmi/hfuzz/.gitignore: -------------------------------------------------------------------------------- 1 | hfuzz_workspace/ 2 | hfuzz_target/ 3 | -------------------------------------------------------------------------------- /vendor/wasmi/hfuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hfuzz" 3 | version = "0.1.0" 4 | authors = ["Sergey Pepyakin "] 5 | 6 | [dependencies] 7 | honggfuzz = "=0.5.9" # Strict equal since hfuzz requires dep and cmd versions to match. 8 | wasmi = { path = ".." } 9 | tempdir = "0.3.6" 10 | wabt = "0.6.0" 11 | -------------------------------------------------------------------------------- /vendor/wasmi/hfuzz/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate honggfuzz; 2 | 3 | extern crate wabt; 4 | extern crate wasmi; 5 | extern crate tempdir; 6 | 7 | use std::fs::File; 8 | use std::io::Write; 9 | use std::process::{Command, Stdio}; 10 | 11 | fn dump_all_into_buf(src: &[u8], buf: &mut [u8; 64]) { 12 | let common_len = usize::min(src.len(), buf.len()); 13 | buf[0..common_len].copy_from_slice(&src[0..common_len]); 14 | } 15 | 16 | fn run_spec(data: &[u8], stdout_msg_buf: &mut [u8; 64], stderr_msg_buf: &mut [u8; 64]) -> Result<(), ()> { 17 | let temp_dir = tempdir::TempDir::new("spec").unwrap(); 18 | let mut seed_path = temp_dir.path().to_path_buf(); 19 | seed_path.push("test.wasm"); 20 | 21 | { 22 | let mut seedfile = 23 | File::create(&seed_path).expect("open temporary file for writing to store fuzzer input"); 24 | seedfile.write_all(data).expect( 25 | "write fuzzer input to temporary file", 26 | ); 27 | seedfile.flush().expect( 28 | "flush fuzzer input to temporary file before starting wasm-opt", 29 | ); 30 | } 31 | 32 | let output = Command::new("wasm") 33 | .arg("-d") 34 | .arg(&seed_path) 35 | .stdout(Stdio::null()) 36 | .stderr(Stdio::null()) 37 | .output() 38 | .expect("failed to execute `wasm`"); 39 | 40 | if output.status.success() { 41 | Ok(()) 42 | } else { 43 | dump_all_into_buf(&output.stdout, stdout_msg_buf); 44 | dump_all_into_buf(&output.stderr, stderr_msg_buf); 45 | Err(()) 46 | } 47 | } 48 | 49 | fn run_wasmi(data: &[u8]) -> Result<(), ()> { 50 | let _ = wasmi::Module::from_buffer(data).map_err(|_| ())?; 51 | Ok(()) 52 | } 53 | 54 | fn main() { 55 | loop { 56 | fuzz!(|data: &[u8]| { 57 | // Keep messages on stack. This should lead to a different stack hashes for 58 | // different error messages. 59 | let mut stdout_msg_buf: [u8; 64] = [0; 64]; 60 | let mut stderr_msg_buf: [u8; 64] = [0; 64]; 61 | 62 | let wasmi_result = run_wasmi(data); 63 | let wasm_result = run_spec(data, &mut stdout_msg_buf, &mut stderr_msg_buf); 64 | 65 | if wasmi_result.is_ok() != wasm_result.is_ok() { 66 | panic!("stdout: {:?}, stderr: {:?}", &stdout_msg_buf[..], &stderr_msg_buf as &[u8]); 67 | } 68 | }); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /vendor/wasmi/hfuzz/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export HFUZZ_RUN_ARGS="--max_file_size 2048" 4 | 5 | die() { echo "$*"; exit 1; } 6 | 7 | command -v wasm || die "spec interpreter 'wasm' is not on PATH"; 8 | 9 | rustup run nightly cargo hfuzz run hfuzz 10 | -------------------------------------------------------------------------------- /vendor/wasmi/res/fixtures/accumulate_u8.wast: -------------------------------------------------------------------------------- 1 | ;; /// @file accumulate_u8.cpp 2 | ;; #include // macro EMSCRIPTEN_KEEPALIVE 3 | ;; #include 4 | ;; #include 5 | ;; #include 6 | ;; extern "C" { 7 | ;; int32_t EMSCRIPTEN_KEEPALIVE accumulate_u8(const int32_t arlen, const uint8_t *ar) { 8 | ;; int32_t arsum = 0; 9 | ;; for (int32_t i=0; i // macro EMSCRIPTEN_KEEPALIVE 3 | ;; #include 4 | ;; extern "C" { 5 | ;; uint32_t EMSCRIPTEN_KEEPALIVE inc_i32(uint32_t param) { 6 | ;; return ++param; 7 | ;; } 8 | ;; } // extern "C" 9 | (module 10 | (type $0 (func (param i32) (result i32))) 11 | (type $1 (func)) 12 | (import "env" "memoryBase" (global $import$0 i32)) 13 | (import "env" "memory" (memory $0 256)) 14 | (import "env" "table" (table 0 anyfunc)) 15 | (import "env" "tableBase" (global $import$3 i32)) 16 | (global $global$0 (mut i32) (i32.const 0)) 17 | (global $global$1 (mut i32) (i32.const 0)) 18 | (export "_inc_i32" (func $0)) 19 | (export "__post_instantiate" (func $2)) 20 | (func $0 (type $0) (param $var$0 i32) (result i32) 21 | (i32.add 22 | (get_local $var$0) 23 | (i32.const 1) 24 | ) 25 | ) 26 | (func $1 (type $1) 27 | (nop) 28 | ) 29 | (func $2 (type $1) 30 | (block $label$0 31 | (set_global $global$0 32 | (get_global $import$0) 33 | ) 34 | (set_global $global$1 35 | (i32.add 36 | (get_global $global$0) 37 | (i32.const 5242880) 38 | ) 39 | ) 40 | (call $1) 41 | ) 42 | ) 43 | ;; custom section "dylink", size 5 44 | ) 45 | 46 | -------------------------------------------------------------------------------- /vendor/wasmi/src/bin/instantiate.rs: -------------------------------------------------------------------------------- 1 | //! Handy utility to test whether the given module deserializes, 2 | //! validates and instantiates successfully. 3 | 4 | extern crate wasmi; 5 | 6 | use std::env::args; 7 | use std::fs::File; 8 | use wasmi::memory_units::*; 9 | use wasmi::{ 10 | Error, FuncInstance, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef, ImportsBuilder, 11 | MemoryDescriptor, MemoryInstance, MemoryRef, Module, ModuleImportResolver, ModuleInstance, 12 | NopExternals, RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef, 13 | }; 14 | 15 | fn load_from_file(filename: &str) -> Module { 16 | use std::io::prelude::*; 17 | let mut file = File::open(filename).unwrap(); 18 | let mut buf = Vec::new(); 19 | file.read_to_end(&mut buf).unwrap(); 20 | Module::from_buffer(buf).unwrap() 21 | } 22 | 23 | struct ResolveAll; 24 | 25 | impl ModuleImportResolver for ResolveAll { 26 | fn resolve_func(&self, _field_name: &str, signature: &Signature) -> Result { 27 | Ok(FuncInstance::alloc_host(signature.clone(), 0)) 28 | } 29 | 30 | fn resolve_global( 31 | &self, 32 | _field_name: &str, 33 | global_type: &GlobalDescriptor, 34 | ) -> Result { 35 | Ok(GlobalInstance::alloc( 36 | RuntimeValue::default(global_type.value_type()), 37 | global_type.is_mutable(), 38 | )) 39 | } 40 | 41 | fn resolve_memory( 42 | &self, 43 | _field_name: &str, 44 | memory_type: &MemoryDescriptor, 45 | ) -> Result { 46 | Ok(MemoryInstance::alloc( 47 | Pages(memory_type.initial() as usize), 48 | memory_type.maximum().map(|m| Pages(m as usize)), 49 | ) 50 | .unwrap()) 51 | } 52 | 53 | fn resolve_table( 54 | &self, 55 | _field_name: &str, 56 | table_type: &TableDescriptor, 57 | ) -> Result { 58 | Ok(TableInstance::alloc(table_type.initial(), table_type.maximum()).unwrap()) 59 | } 60 | } 61 | 62 | fn main() { 63 | let args: Vec<_> = args().collect(); 64 | if args.len() != 2 { 65 | println!("Usage: {} ", args[0]); 66 | return; 67 | } 68 | let module = load_from_file(&args[1]); 69 | let _ = ModuleInstance::new( 70 | &module, 71 | &ImportsBuilder::default() 72 | // Well known imports. 73 | .with_resolver("env", &ResolveAll) 74 | .with_resolver("global", &ResolveAll) 75 | .with_resolver("foo", &ResolveAll) 76 | .with_resolver("global.Math", &ResolveAll) 77 | .with_resolver("asm2wasm", &ResolveAll) 78 | .with_resolver("spectest", &ResolveAll), 79 | ) 80 | .expect("Failed to instantiate module") 81 | .run_start(&mut NopExternals) 82 | .expect("Failed to run start function in module"); 83 | } 84 | -------------------------------------------------------------------------------- /vendor/wasmi/src/global.rs: -------------------------------------------------------------------------------- 1 | use alloc::rc::Rc; 2 | use core::cell::Cell; 3 | use parity_wasm::elements::ValueType as EValueType; 4 | use types::ValueType; 5 | use value::RuntimeValue; 6 | use Error; 7 | 8 | /// Reference to a global variable (See [`GlobalInstance`] for details). 9 | /// 10 | /// This reference has a reference-counting semantics. 11 | /// 12 | /// [`GlobalInstance`]: struct.GlobalInstance.html 13 | #[derive(Clone, Debug)] 14 | pub struct GlobalRef(Rc); 15 | 16 | impl ::core::ops::Deref for GlobalRef { 17 | type Target = GlobalInstance; 18 | fn deref(&self) -> &GlobalInstance { 19 | &self.0 20 | } 21 | } 22 | 23 | /// Runtime representation of a global variable (or `global` for short). 24 | /// 25 | /// Global contains a value of a specified type and flag which specifies whether this 26 | /// global are mutable or immutable. Neither type of the value nor immutability can't be changed 27 | /// after creation. 28 | /// 29 | /// Attempt to change value of immutable global or to change type of 30 | /// the value (e.g. assign [`I32`] value to a global that was created with [`I64`] type) will lead to an error. 31 | /// 32 | /// [`I32`]: enum.RuntimeValue.html#variant.I32 33 | /// [`I64`]: enum.RuntimeValue.html#variant.I64 34 | #[derive(Debug)] 35 | pub struct GlobalInstance { 36 | val: Cell, 37 | mutable: bool, 38 | } 39 | 40 | impl GlobalInstance { 41 | /// Allocate a global variable instance. 42 | /// 43 | /// Since it is possible to export only immutable globals, 44 | /// users likely want to set `mutable` to `false`. 45 | pub fn alloc(val: RuntimeValue, mutable: bool) -> GlobalRef { 46 | GlobalRef(Rc::new(GlobalInstance { 47 | val: Cell::new(val), 48 | mutable, 49 | })) 50 | } 51 | 52 | /// Change the value of this global variable. 53 | /// 54 | /// # Errors 55 | /// 56 | /// Returns `Err` if this global isn't mutable or if 57 | /// type of `val` doesn't match global's type. 58 | pub fn set(&self, val: RuntimeValue) -> Result<(), Error> { 59 | if !self.mutable { 60 | return Err(Error::Global( 61 | "Attempt to change an immutable variable".into(), 62 | )); 63 | } 64 | if self.value_type() != val.value_type() { 65 | return Err(Error::Global("Attempt to change variable type".into())); 66 | } 67 | self.val.set(val); 68 | Ok(()) 69 | } 70 | 71 | /// Get the value of this global variable. 72 | pub fn get(&self) -> RuntimeValue { 73 | self.val.get() 74 | } 75 | 76 | /// Returns if this global variable is mutable. 77 | /// 78 | /// Note: Imported and/or exported globals are always immutable. 79 | pub fn is_mutable(&self) -> bool { 80 | self.mutable 81 | } 82 | 83 | /// Returns value type of this global variable. 84 | pub fn value_type(&self) -> ValueType { 85 | self.val.get().value_type() 86 | } 87 | 88 | pub(crate) fn elements_value_type(&self) -> EValueType { 89 | self.value_type().into_elements() 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /vendor/wasmi/src/host.rs: -------------------------------------------------------------------------------- 1 | use core::any::TypeId; 2 | use value::{FromRuntimeValue, RuntimeValue}; 3 | use {Trap, TrapKind}; 4 | 5 | /// Wrapper around slice of [`RuntimeValue`] for using it 6 | /// as an argument list conveniently. 7 | /// 8 | /// [`RuntimeValue`]: enum.RuntimeValue.html 9 | #[derive(Debug)] 10 | pub struct RuntimeArgs<'a>(&'a [RuntimeValue]); 11 | 12 | impl<'a> From<&'a [RuntimeValue]> for RuntimeArgs<'a> { 13 | fn from(inner: &'a [RuntimeValue]) -> Self { 14 | RuntimeArgs(inner) 15 | } 16 | } 17 | 18 | impl<'a> AsRef<[RuntimeValue]> for RuntimeArgs<'a> { 19 | fn as_ref(&self) -> &[RuntimeValue] { 20 | self.0 21 | } 22 | } 23 | 24 | impl<'a> RuntimeArgs<'a> { 25 | /// Extract argument by index `idx`. 26 | /// 27 | /// # Errors 28 | /// 29 | /// Returns `Err` if cast is invalid or not enough arguments. 30 | pub fn nth_checked(&self, idx: usize) -> Result 31 | where 32 | T: FromRuntimeValue, 33 | { 34 | Ok(self 35 | .nth_value_checked(idx)? 36 | .try_into() 37 | .ok_or_else(|| TrapKind::UnexpectedSignature)?) 38 | } 39 | 40 | /// Extract argument as a [`RuntimeValue`] by index `idx`. 41 | /// 42 | /// # Errors 43 | /// 44 | /// Returns `Err` if this list has not enough arguments. 45 | /// 46 | /// [`RuntimeValue`]: enum.RuntimeValue.html 47 | pub fn nth_value_checked(&self, idx: usize) -> Result { 48 | if self.0.len() <= idx { 49 | return Err(TrapKind::UnexpectedSignature.into()); 50 | } 51 | Ok(self.0[idx]) 52 | } 53 | 54 | /// Extract argument by index `idx`. 55 | /// 56 | /// # Panics 57 | /// 58 | /// Panics if cast is invalid or not enough arguments. 59 | pub fn nth(&self, idx: usize) -> T 60 | where 61 | T: FromRuntimeValue, 62 | { 63 | let value = self.nth_value_checked(idx).expect("Invalid argument index"); 64 | value.try_into().expect("Unexpected argument type") 65 | } 66 | 67 | /// Total number of arguments 68 | pub fn len(&self) -> usize { 69 | self.0.len() 70 | } 71 | } 72 | 73 | /// Trait that allows the host to return custom error. 74 | /// 75 | /// It should be useful for representing custom traps, 76 | /// troubles at instantiation time or other host specific conditions. 77 | /// 78 | /// # Examples 79 | /// 80 | /// ```rust 81 | /// use std::fmt; 82 | /// use wasmi::{Error, HostError}; 83 | /// 84 | /// #[derive(Debug)] 85 | /// struct MyError { 86 | /// code: u32, 87 | /// } 88 | /// 89 | /// impl fmt::Display for MyError { 90 | /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 91 | /// write!(f, "MyError, code={}", self.code) 92 | /// } 93 | /// } 94 | /// 95 | /// impl HostError for MyError { } 96 | /// 97 | /// fn failable_fn() -> Result<(), Error> { 98 | /// let my_error = MyError { code: 1312 }; 99 | /// Err(Error::Host(Box::new(my_error))) 100 | /// } 101 | /// 102 | /// match failable_fn() { 103 | /// Err(Error::Host(host_error)) => { 104 | /// let my_error = host_error.downcast_ref::().unwrap(); 105 | /// assert_eq!(my_error.code, 1312); 106 | /// } 107 | /// _ => panic!(), 108 | /// } 109 | /// ``` 110 | pub trait HostError: 'static + ::core::fmt::Display + ::core::fmt::Debug + Send + Sync { 111 | #[doc(hidden)] 112 | fn __private_get_type_id__(&self) -> TypeId { 113 | TypeId::of::() 114 | } 115 | } 116 | 117 | impl HostError { 118 | /// Attempt to downcast this `HostError` to a concrete type by reference. 119 | pub fn downcast_ref(&self) -> Option<&T> { 120 | if self.__private_get_type_id__() == TypeId::of::() { 121 | unsafe { Some(&*(self as *const HostError as *const T)) } 122 | } else { 123 | None 124 | } 125 | } 126 | 127 | /// Attempt to downcast this `HostError` to a concrete type by mutable 128 | /// reference. 129 | pub fn downcast_mut(&mut self) -> Option<&mut T> { 130 | if self.__private_get_type_id__() == TypeId::of::() { 131 | unsafe { Some(&mut *(self as *mut HostError as *mut T)) } 132 | } else { 133 | None 134 | } 135 | } 136 | } 137 | 138 | /// Trait that allows to implement host functions. 139 | /// 140 | /// # Examples 141 | /// 142 | /// ```rust 143 | /// use wasmi::{ 144 | /// Externals, RuntimeValue, RuntimeArgs, Error, ModuleImportResolver, 145 | /// FuncRef, ValueType, Signature, FuncInstance, Trap, 146 | /// }; 147 | /// 148 | /// struct HostExternals { 149 | /// counter: usize, 150 | /// } 151 | /// 152 | /// const ADD_FUNC_INDEX: usize = 0; 153 | /// 154 | /// impl Externals for HostExternals { 155 | /// fn invoke_index( 156 | /// &mut self, 157 | /// index: usize, 158 | /// args: RuntimeArgs, 159 | /// ) -> Result, Trap> { 160 | /// match index { 161 | /// ADD_FUNC_INDEX => { 162 | /// let a: u32 = args.nth_checked(0)?; 163 | /// let b: u32 = args.nth_checked(1)?; 164 | /// let result = a + b; 165 | /// 166 | /// Ok(Some(RuntimeValue::I32(result as i32))) 167 | /// } 168 | /// _ => panic!("Unimplemented function at {}", index), 169 | /// } 170 | /// } 171 | /// } 172 | /// 173 | /// impl HostExternals { 174 | /// fn check_signature( 175 | /// &self, 176 | /// index: usize, 177 | /// signature: &Signature 178 | /// ) -> bool { 179 | /// let (params, ret_ty): (&[ValueType], Option) = match index { 180 | /// ADD_FUNC_INDEX => (&[ValueType::I32, ValueType::I32], Some(ValueType::I32)), 181 | /// _ => return false, 182 | /// }; 183 | /// signature.params() == params && signature.return_type() == ret_ty 184 | /// } 185 | /// } 186 | /// 187 | /// impl ModuleImportResolver for HostExternals { 188 | /// fn resolve_func( 189 | /// &self, 190 | /// field_name: &str, 191 | /// signature: &Signature 192 | /// ) -> Result { 193 | /// let index = match field_name { 194 | /// "add" => ADD_FUNC_INDEX, 195 | /// _ => { 196 | /// return Err(Error::Instantiation( 197 | /// format!("Export {} not found", field_name), 198 | /// )) 199 | /// } 200 | /// }; 201 | /// 202 | /// if !self.check_signature(index, signature) { 203 | /// return Err(Error::Instantiation( 204 | /// format!("Export {} has a bad signature", field_name) 205 | /// )); 206 | /// } 207 | /// 208 | /// Ok(FuncInstance::alloc_host( 209 | /// Signature::new(&[ValueType::I32, ValueType::I32][..], Some(ValueType::I32)), 210 | /// index, 211 | /// )) 212 | /// } 213 | /// } 214 | /// ``` 215 | pub trait Externals { 216 | /// Perform invoke of a host function by specified `index`. 217 | fn invoke_index( 218 | &mut self, 219 | index: usize, 220 | args: RuntimeArgs, 221 | ) -> Result, Trap>; 222 | } 223 | 224 | /// Implementation of [`Externals`] that just traps on [`invoke_index`]. 225 | /// 226 | /// [`Externals`]: trait.Externals.html 227 | /// [`invoke_index`]: trait.Externals.html#tymethod.invoke_index 228 | pub struct NopExternals; 229 | 230 | impl Externals for NopExternals { 231 | fn invoke_index( 232 | &mut self, 233 | _index: usize, 234 | _args: RuntimeArgs, 235 | ) -> Result, Trap> { 236 | Err(TrapKind::Unreachable.into()) 237 | } 238 | } 239 | 240 | #[cfg(test)] 241 | mod tests { 242 | 243 | use super::{HostError, RuntimeArgs}; 244 | use value::RuntimeValue; 245 | 246 | #[test] 247 | fn i32_runtime_args() { 248 | let args: RuntimeArgs = (&[RuntimeValue::I32(0)][..]).into(); 249 | let val: i32 = args.nth_checked(0).unwrap(); 250 | assert_eq!(val, 0); 251 | } 252 | 253 | #[test] 254 | fn i64_invalid_arg_cast() { 255 | let args: RuntimeArgs = (&[RuntimeValue::I64(90534534545322)][..]).into(); 256 | assert!(args.nth_checked::(0).is_err()); 257 | } 258 | 259 | // Tests that `HostError` trait is object safe. 260 | fn _host_error_is_object_safe(_: &HostError) {} 261 | } 262 | -------------------------------------------------------------------------------- /vendor/wasmi/src/imports.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports)] 2 | use alloc::prelude::v1::*; 3 | 4 | #[cfg(not(feature = "std"))] 5 | use hashbrown::HashMap; 6 | #[cfg(feature = "std")] 7 | use std::collections::HashMap; 8 | 9 | use func::FuncRef; 10 | use global::GlobalRef; 11 | use memory::MemoryRef; 12 | use module::ModuleRef; 13 | use table::TableRef; 14 | use types::{GlobalDescriptor, MemoryDescriptor, TableDescriptor}; 15 | use {Error, Signature}; 16 | 17 | /// Resolver of a module's dependencies. 18 | /// 19 | /// A module have dependencies in a form of a list of imports (i.e. 20 | /// tuple of a (`module_name`, `field_name`, `descriptor`)). 21 | /// 22 | /// The job of implementations of this trait is to provide on each 23 | /// import a corresponding concrete reference. 24 | /// 25 | /// For simple use-cases you can use [`ImportsBuilder`]. 26 | /// 27 | /// [`ImportsBuilder`]: struct.ImportsBuilder.html 28 | pub trait ImportResolver { 29 | /// Resolve a function. 30 | /// 31 | /// Returned function should match given `signature`, i.e. all parameter types and return value should have exact match. 32 | /// Otherwise, link-time error will occur. 33 | fn resolve_func( 34 | &self, 35 | _module_name: &str, 36 | field_name: &str, 37 | _signature: &Signature, 38 | ) -> Result; 39 | 40 | /// Resolve a global variable. 41 | /// 42 | /// Returned global should match given `descriptor`, i.e. type and mutability 43 | /// should match. Otherwise, link-time error will occur. 44 | fn resolve_global( 45 | &self, 46 | module_name: &str, 47 | field_name: &str, 48 | descriptor: &GlobalDescriptor, 49 | ) -> Result; 50 | 51 | /// Resolve a memory. 52 | /// 53 | /// Returned memory should match requested memory (described by the `descriptor`), 54 | /// i.e. initial size of a returned memory should be equal or larger than requested memory. 55 | /// Furthermore, if requested memory have maximum size, returned memory either should have 56 | /// equal or larger maximum size or have no maximum size at all. 57 | /// If returned memory doesn't match the requested then link-time error will occur. 58 | fn resolve_memory( 59 | &self, 60 | module_name: &str, 61 | field_name: &str, 62 | descriptor: &MemoryDescriptor, 63 | ) -> Result; 64 | 65 | /// Resolve a table. 66 | /// 67 | /// Returned table should match requested table (described by the `descriptor`), 68 | /// i.e. initial size of a returned table should be equal or larger than requested table. 69 | /// Furthermore, if requested memory have maximum size, returned memory either should have 70 | /// equal or larger maximum size or have no maximum size at all. 71 | /// If returned table doesn't match the requested then link-time error will occur. 72 | fn resolve_table( 73 | &self, 74 | module_name: &str, 75 | field_name: &str, 76 | descriptor: &TableDescriptor, 77 | ) -> Result; 78 | } 79 | 80 | /// Convenience builder of [`ImportResolver`]. 81 | /// 82 | /// With help of this builder, you can easily create [`ImportResolver`], just by 83 | /// adding needed [resolvers][`ModuleImportResolver`] by names. 84 | /// 85 | /// # Examples 86 | /// 87 | /// ```rust 88 | /// use wasmi::{ModuleInstance, ImportsBuilder}; 89 | /// # 90 | /// # struct EnvModuleResolver; 91 | /// # impl ::wasmi::ModuleImportResolver for EnvModuleResolver { } 92 | /// # fn func() -> Result<(), ::wasmi::Error> { 93 | /// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); 94 | /// # let other_instance = ModuleInstance::new(&module, &ImportsBuilder::default())?.assert_no_start(); 95 | /// 96 | /// let imports = ImportsBuilder::new() 97 | /// .with_resolver("env", &EnvModuleResolver) 98 | /// // Note, that ModuleInstance can be a resolver too. 99 | /// .with_resolver("other_instance", &other_instance); 100 | /// let instance = ModuleInstance::new(&module, &imports)?.assert_no_start(); 101 | /// 102 | /// # Ok(()) 103 | /// # } 104 | /// ``` 105 | /// 106 | /// [`ImportResolver`]: trait.ImportResolver.html 107 | /// [`ModuleImportResolver`]: trait.ModuleImportResolver.html 108 | pub struct ImportsBuilder<'a> { 109 | modules: HashMap, 110 | } 111 | 112 | impl<'a> Default for ImportsBuilder<'a> { 113 | fn default() -> Self { 114 | Self::new() 115 | } 116 | } 117 | 118 | impl<'a> ImportsBuilder<'a> { 119 | /// Create an empty `ImportsBuilder`. 120 | pub fn new() -> ImportsBuilder<'a> { 121 | ImportsBuilder { 122 | modules: HashMap::new(), 123 | } 124 | } 125 | 126 | /// Register an resolver by a name. 127 | pub fn with_resolver>( 128 | mut self, 129 | name: N, 130 | resolver: &'a ModuleImportResolver, 131 | ) -> Self { 132 | self.modules.insert(name.into(), resolver); 133 | self 134 | } 135 | 136 | /// Register an resolver by a name. 137 | /// 138 | /// Mutable borrowed version. 139 | pub fn push_resolver>(&mut self, name: N, resolver: &'a ModuleImportResolver) { 140 | self.modules.insert(name.into(), resolver); 141 | } 142 | 143 | fn resolver(&self, name: &str) -> Option<&ModuleImportResolver> { 144 | self.modules.get(name).cloned() 145 | } 146 | } 147 | 148 | impl<'a> ImportResolver for ImportsBuilder<'a> { 149 | fn resolve_func( 150 | &self, 151 | module_name: &str, 152 | field_name: &str, 153 | signature: &Signature, 154 | ) -> Result { 155 | self.resolver(module_name) 156 | .ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)))? 157 | .resolve_func(field_name, signature) 158 | } 159 | 160 | fn resolve_global( 161 | &self, 162 | module_name: &str, 163 | field_name: &str, 164 | global_type: &GlobalDescriptor, 165 | ) -> Result { 166 | self.resolver(module_name) 167 | .ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)))? 168 | .resolve_global(field_name, global_type) 169 | } 170 | 171 | fn resolve_memory( 172 | &self, 173 | module_name: &str, 174 | field_name: &str, 175 | memory_type: &MemoryDescriptor, 176 | ) -> Result { 177 | self.resolver(module_name) 178 | .ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)))? 179 | .resolve_memory(field_name, memory_type) 180 | } 181 | 182 | fn resolve_table( 183 | &self, 184 | module_name: &str, 185 | field_name: &str, 186 | table_type: &TableDescriptor, 187 | ) -> Result { 188 | self.resolver(module_name) 189 | .ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)))? 190 | .resolve_table(field_name, table_type) 191 | } 192 | } 193 | 194 | /// Version of [`ImportResolver`] specialized for a single module. 195 | /// 196 | /// [`ImportResolver`]: trait.ImportResolver.html 197 | pub trait ModuleImportResolver { 198 | /// Resolve a function. 199 | /// 200 | /// See [`ImportResolver::resolve_func`] for details. 201 | /// 202 | /// [`ImportResolver::resolve_func`]: trait.ImportResolver.html#tymethod.resolve_func 203 | fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result { 204 | Err(Error::Instantiation(format!( 205 | "Export {} not found", 206 | field_name 207 | ))) 208 | } 209 | 210 | /// Resolve a global variable. 211 | /// 212 | /// See [`ImportResolver::resolve_global`] for details. 213 | /// 214 | /// [`ImportResolver::resolve_global`]: trait.ImportResolver.html#tymethod.resolve_global 215 | fn resolve_global( 216 | &self, 217 | field_name: &str, 218 | _global_type: &GlobalDescriptor, 219 | ) -> Result { 220 | Err(Error::Instantiation(format!( 221 | "Export {} not found", 222 | field_name 223 | ))) 224 | } 225 | 226 | /// Resolve a memory. 227 | /// 228 | /// See [`ImportResolver::resolve_memory`] for details. 229 | /// 230 | /// [`ImportResolver::resolve_memory`]: trait.ImportResolver.html#tymethod.resolve_memory 231 | fn resolve_memory( 232 | &self, 233 | field_name: &str, 234 | _memory_type: &MemoryDescriptor, 235 | ) -> Result { 236 | Err(Error::Instantiation(format!( 237 | "Export {} not found", 238 | field_name 239 | ))) 240 | } 241 | 242 | /// Resolve a table. 243 | /// 244 | /// See [`ImportResolver::resolve_table`] for details. 245 | /// 246 | /// [`ImportResolver::resolve_table`]: trait.ImportResolver.html#tymethod.resolve_table 247 | fn resolve_table( 248 | &self, 249 | field_name: &str, 250 | _table_type: &TableDescriptor, 251 | ) -> Result { 252 | Err(Error::Instantiation(format!( 253 | "Export {} not found", 254 | field_name 255 | ))) 256 | } 257 | } 258 | 259 | impl ModuleImportResolver for ModuleRef { 260 | fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result { 261 | Ok(self 262 | .export_by_name(field_name) 263 | .ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))? 264 | .as_func() 265 | .cloned() 266 | .ok_or_else(|| { 267 | Error::Instantiation(format!("Export {} is not a function", field_name)) 268 | })?) 269 | } 270 | 271 | fn resolve_global( 272 | &self, 273 | field_name: &str, 274 | _global_type: &GlobalDescriptor, 275 | ) -> Result { 276 | Ok(self 277 | .export_by_name(field_name) 278 | .ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))? 279 | .as_global() 280 | .cloned() 281 | .ok_or_else(|| { 282 | Error::Instantiation(format!("Export {} is not a global", field_name)) 283 | })?) 284 | } 285 | 286 | fn resolve_memory( 287 | &self, 288 | field_name: &str, 289 | _memory_type: &MemoryDescriptor, 290 | ) -> Result { 291 | Ok(self 292 | .export_by_name(field_name) 293 | .ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))? 294 | .as_memory() 295 | .cloned() 296 | .ok_or_else(|| { 297 | Error::Instantiation(format!("Export {} is not a memory", field_name)) 298 | })?) 299 | } 300 | 301 | fn resolve_table( 302 | &self, 303 | field_name: &str, 304 | _table_type: &TableDescriptor, 305 | ) -> Result { 306 | Ok(self 307 | .export_by_name(field_name) 308 | .ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))? 309 | .as_table() 310 | .cloned() 311 | .ok_or_else(|| Error::Instantiation(format!("Export {} is not a table", field_name)))?) 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /vendor/wasmi/src/nan_preserving_float.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] 2 | 3 | #[cfg(not(feature = "std"))] 4 | use libm::{F32Ext, F64Ext}; 5 | 6 | use core::cmp::{Ordering, PartialEq, PartialOrd}; 7 | use core::ops::{Add, Div, Mul, Neg, Rem, Sub}; 8 | 9 | macro_rules! impl_binop { 10 | ($for:ident, $is:ident, $op:ident, $func_name:ident) => { 11 | impl> $op for $for { 12 | type Output = Self; 13 | 14 | fn $func_name(self, other: T) -> Self { 15 | $for( 16 | $op::$func_name($is::from_bits(self.0), $is::from_bits(other.into().0)) 17 | .to_bits(), 18 | ) 19 | } 20 | } 21 | }; 22 | } 23 | 24 | macro_rules! float { 25 | ($for:ident, $rep:ident, $is:ident) => { 26 | float!( 27 | $for, 28 | $rep, 29 | $is, 30 | 1 << (::core::mem::size_of::<$is>() * 8 - 1) 31 | ); 32 | }; 33 | ($for:ident, $rep:ident, $is:ident, $sign_bit:expr) => { 34 | #[derive(Copy, Clone)] 35 | pub struct $for($rep); 36 | 37 | impl_binop!($for, $is, Add, add); 38 | impl_binop!($for, $is, Sub, sub); 39 | impl_binop!($for, $is, Mul, mul); 40 | impl_binop!($for, $is, Div, div); 41 | impl_binop!($for, $is, Rem, rem); 42 | 43 | impl $for { 44 | pub fn from_bits(other: $rep) -> Self { 45 | $for(other) 46 | } 47 | 48 | pub fn to_bits(self) -> $rep { 49 | self.0 50 | } 51 | 52 | pub fn from_float(fl: $is) -> Self { 53 | fl.into() 54 | } 55 | 56 | pub fn to_float(self) -> $is { 57 | self.into() 58 | } 59 | 60 | pub fn is_nan(self) -> bool { 61 | self.to_float().is_nan() 62 | } 63 | 64 | pub fn abs(self) -> Self { 65 | $for(self.0 & !$sign_bit) 66 | } 67 | 68 | pub fn fract(self) -> Self { 69 | self.to_float().fract().into() 70 | } 71 | 72 | pub fn min(self, other: Self) -> Self { 73 | Self::from(self.to_float().min(other.to_float())) 74 | } 75 | 76 | pub fn max(self, other: Self) -> Self { 77 | Self::from(self.to_float().max(other.to_float())) 78 | } 79 | } 80 | 81 | impl From<$is> for $for { 82 | fn from(other: $is) -> $for { 83 | $for(other.to_bits()) 84 | } 85 | } 86 | 87 | impl From<$for> for $is { 88 | fn from(other: $for) -> $is { 89 | <$is>::from_bits(other.0) 90 | } 91 | } 92 | 93 | impl Neg for $for { 94 | type Output = Self; 95 | 96 | fn neg(self) -> Self { 97 | $for(self.0 ^ $sign_bit) 98 | } 99 | } 100 | 101 | impl + Copy> PartialEq for $for { 102 | fn eq(&self, other: &T) -> bool { 103 | $is::from(*self) == $is::from((*other).into()) 104 | } 105 | } 106 | 107 | impl + Copy> PartialOrd for $for { 108 | fn partial_cmp(&self, other: &T) -> Option { 109 | $is::from(*self).partial_cmp(&$is::from((*other).into())) 110 | } 111 | } 112 | 113 | impl ::core::fmt::Debug for $for { 114 | fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { 115 | $is::from(*self).fmt(f) 116 | } 117 | } 118 | }; 119 | } 120 | 121 | float!(F32, u32, f32); 122 | float!(F64, u64, f64); 123 | 124 | impl From for F32 { 125 | fn from(other: u32) -> Self { 126 | Self::from_bits(other) 127 | } 128 | } 129 | 130 | impl From for u32 { 131 | fn from(other: F32) -> Self { 132 | other.to_bits() 133 | } 134 | } 135 | 136 | impl From for F64 { 137 | fn from(other: u64) -> Self { 138 | Self::from_bits(other) 139 | } 140 | } 141 | 142 | impl From for u64 { 143 | fn from(other: F64) -> Self { 144 | other.to_bits() 145 | } 146 | } 147 | 148 | #[cfg(test)] 149 | mod tests { 150 | extern crate rand; 151 | 152 | use self::rand::Rng; 153 | 154 | use super::{F32, F64}; 155 | 156 | use core::{ 157 | fmt::Debug, 158 | iter, 159 | ops::{Add, Div, Mul, Neg, Sub}, 160 | }; 161 | 162 | fn test_ops(iter: I) 163 | where 164 | T: Add 165 | + Div 166 | + Mul 167 | + Sub 168 | + Neg 169 | + Copy 170 | + Debug 171 | + PartialEq, 172 | F: Into 173 | + Add 174 | + Div 175 | + Mul 176 | + Sub 177 | + Neg 178 | + Copy 179 | + Debug, 180 | I: IntoIterator, 181 | { 182 | for (a, b) in iter { 183 | assert_eq!((a + b).into(), a.into() + b.into()); 184 | assert_eq!((a - b).into(), a.into() - b.into()); 185 | assert_eq!((a * b).into(), a.into() * b.into()); 186 | assert_eq!((a / b).into(), a.into() / b.into()); 187 | assert_eq!((-a).into(), -a.into()); 188 | assert_eq!((-b).into(), -b.into()); 189 | } 190 | } 191 | 192 | #[test] 193 | fn test_ops_f32() { 194 | let mut rng = rand::thread_rng(); 195 | let iter = iter::repeat(()).map(|_| rng.gen()); 196 | 197 | test_ops::(iter.take(1000)); 198 | } 199 | 200 | #[test] 201 | fn test_ops_f64() { 202 | let mut rng = rand::thread_rng(); 203 | let iter = iter::repeat(()).map(|_| rng.gen()); 204 | 205 | test_ops::(iter.take(1000)); 206 | } 207 | 208 | #[test] 209 | fn test_neg_nan_f32() { 210 | assert_eq!((-F32(0xff80_3210)).0, 0x7f80_3210); 211 | } 212 | 213 | #[test] 214 | fn test_neg_nan_f64() { 215 | assert_eq!((-F64(0xff80_3210_0000_0000)).0, 0x7f80_3210_0000_0000); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /vendor/wasmi/src/prepare/mod.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports)] 2 | use alloc::prelude::v1::*; 3 | 4 | use crate::{ 5 | isa, 6 | validation::{validate_module, Error, Validator}, 7 | }; 8 | use parity_wasm::elements::Module; 9 | 10 | mod compile; 11 | 12 | #[cfg(test)] 13 | mod tests; 14 | 15 | #[derive(Clone)] 16 | pub struct CompiledModule { 17 | pub code_map: Vec, 18 | pub module: Module, 19 | } 20 | 21 | pub struct WasmiValidation { 22 | code_map: Vec, 23 | } 24 | 25 | // This implementation of `Validation` is compiling wasm code at the 26 | // validation time. 27 | impl Validator for WasmiValidation { 28 | type Output = Vec; 29 | type FuncValidator = compile::Compiler; 30 | fn new(_module: &Module) -> Self { 31 | WasmiValidation { 32 | // TODO: with capacity? 33 | code_map: Vec::new(), 34 | } 35 | } 36 | fn on_function_validated(&mut self, _index: u32, output: isa::Instructions) { 37 | self.code_map.push(output); 38 | } 39 | fn finish(self) -> Vec { 40 | self.code_map 41 | } 42 | } 43 | 44 | /// Validate a module and compile it to the internal representation. 45 | pub fn compile_module(module: Module) -> Result { 46 | let code_map = validate_module::(&module)?; 47 | Ok(CompiledModule { module, code_map }) 48 | } 49 | 50 | /// Verify that the module doesn't use floating point instructions or types. 51 | /// 52 | /// Returns `Err` if 53 | /// 54 | /// - Any of function bodies uses a floating pointer instruction (an instruction that 55 | /// consumes or produces a value of a floating point type) 56 | /// - If a floating point type used in a definition of a function. 57 | pub fn deny_floating_point(module: &Module) -> Result<(), Error> { 58 | use parity_wasm::elements::{ 59 | Instruction::{self, *}, 60 | Type, ValueType, 61 | }; 62 | 63 | if let Some(code) = module.code_section() { 64 | for op in code.bodies().iter().flat_map(|body| body.code().elements()) { 65 | macro_rules! match_eq { 66 | ($pattern:pat) => { 67 | |val| if let $pattern = *val { true } else { false } 68 | }; 69 | } 70 | 71 | const DENIED: &[fn(&Instruction) -> bool] = &[ 72 | match_eq!(F32Load(_, _)), 73 | match_eq!(F64Load(_, _)), 74 | match_eq!(F32Store(_, _)), 75 | match_eq!(F64Store(_, _)), 76 | match_eq!(F32Const(_)), 77 | match_eq!(F64Const(_)), 78 | match_eq!(F32Eq), 79 | match_eq!(F32Ne), 80 | match_eq!(F32Lt), 81 | match_eq!(F32Gt), 82 | match_eq!(F32Le), 83 | match_eq!(F32Ge), 84 | match_eq!(F64Eq), 85 | match_eq!(F64Ne), 86 | match_eq!(F64Lt), 87 | match_eq!(F64Gt), 88 | match_eq!(F64Le), 89 | match_eq!(F64Ge), 90 | match_eq!(F32Abs), 91 | match_eq!(F32Neg), 92 | match_eq!(F32Ceil), 93 | match_eq!(F32Floor), 94 | match_eq!(F32Trunc), 95 | match_eq!(F32Nearest), 96 | match_eq!(F32Sqrt), 97 | match_eq!(F32Add), 98 | match_eq!(F32Sub), 99 | match_eq!(F32Mul), 100 | match_eq!(F32Div), 101 | match_eq!(F32Min), 102 | match_eq!(F32Max), 103 | match_eq!(F32Copysign), 104 | match_eq!(F64Abs), 105 | match_eq!(F64Neg), 106 | match_eq!(F64Ceil), 107 | match_eq!(F64Floor), 108 | match_eq!(F64Trunc), 109 | match_eq!(F64Nearest), 110 | match_eq!(F64Sqrt), 111 | match_eq!(F64Add), 112 | match_eq!(F64Sub), 113 | match_eq!(F64Mul), 114 | match_eq!(F64Div), 115 | match_eq!(F64Min), 116 | match_eq!(F64Max), 117 | match_eq!(F64Copysign), 118 | match_eq!(F32ConvertSI32), 119 | match_eq!(F32ConvertUI32), 120 | match_eq!(F32ConvertSI64), 121 | match_eq!(F32ConvertUI64), 122 | match_eq!(F32DemoteF64), 123 | match_eq!(F64ConvertSI32), 124 | match_eq!(F64ConvertUI32), 125 | match_eq!(F64ConvertSI64), 126 | match_eq!(F64ConvertUI64), 127 | match_eq!(F64PromoteF32), 128 | match_eq!(F32ReinterpretI32), 129 | match_eq!(F64ReinterpretI64), 130 | match_eq!(I32TruncSF32), 131 | match_eq!(I32TruncUF32), 132 | match_eq!(I32TruncSF64), 133 | match_eq!(I32TruncUF64), 134 | match_eq!(I64TruncSF32), 135 | match_eq!(I64TruncUF32), 136 | match_eq!(I64TruncSF64), 137 | match_eq!(I64TruncUF64), 138 | match_eq!(I32ReinterpretF32), 139 | match_eq!(I64ReinterpretF64), 140 | ]; 141 | 142 | if DENIED.iter().any(|is_denied| is_denied(op)) { 143 | return Err(Error(format!("Floating point operation denied: {:?}", op))); 144 | } 145 | } 146 | } 147 | 148 | if let (Some(sec), Some(types)) = (module.function_section(), module.type_section()) { 149 | let types = types.types(); 150 | 151 | for sig in sec.entries() { 152 | if let Some(typ) = types.get(sig.type_ref() as usize) { 153 | match *typ { 154 | Type::Function(ref func) => { 155 | if func 156 | .params() 157 | .iter() 158 | .chain(func.return_type().as_ref()) 159 | .any(|&typ| typ == ValueType::F32 || typ == ValueType::F64) 160 | { 161 | return Err(Error(format!("Use of floating point types denied"))); 162 | } 163 | } 164 | } 165 | } 166 | } 167 | } 168 | 169 | Ok(()) 170 | } 171 | -------------------------------------------------------------------------------- /vendor/wasmi/src/table.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports)] 2 | use alloc::prelude::v1::*; 3 | use alloc::rc::Rc; 4 | use core::cell::RefCell; 5 | use core::fmt; 6 | use core::u32; 7 | use func::FuncRef; 8 | use module::check_limits; 9 | use parity_wasm::elements::ResizableLimits; 10 | use Error; 11 | 12 | /// Reference to a table (See [`TableInstance`] for details). 13 | /// 14 | /// This reference has a reference-counting semantics. 15 | /// 16 | /// [`TableInstance`]: struct.TableInstance.html 17 | /// 18 | #[derive(Clone, Debug)] 19 | pub struct TableRef(Rc); 20 | 21 | impl ::core::ops::Deref for TableRef { 22 | type Target = TableInstance; 23 | fn deref(&self) -> &TableInstance { 24 | &self.0 25 | } 26 | } 27 | 28 | /// Runtime representation of a table. 29 | /// 30 | /// A table is a array of untyped functions. It allows wasm code to call functions 31 | /// indirectly through a dynamic index into a table. For example, this allows emulating function 32 | /// pointers by way of table indices. 33 | /// 34 | /// Table is created with an initial size but can be grown dynamically via [`grow`] method. 35 | /// Growth can be limited by an optional maximum size. 36 | /// 37 | /// In future, a table might be extended to be able to hold not only functions but different types. 38 | /// 39 | /// [`grow`]: #method.grow 40 | /// 41 | pub struct TableInstance { 42 | /// Table limits. 43 | limits: ResizableLimits, 44 | /// Table memory buffer. 45 | buffer: RefCell>>, 46 | } 47 | 48 | impl fmt::Debug for TableInstance { 49 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 50 | f.debug_struct("TableInstance") 51 | .field("limits", &self.limits) 52 | .field("buffer.len", &self.buffer.borrow().len()) 53 | .finish() 54 | } 55 | } 56 | 57 | impl TableInstance { 58 | /// Allocate a table instance. 59 | /// 60 | /// The table allocated with initial size, specified by `initial_size`. 61 | /// Maximum size can be specified by `maximum_size`. 62 | /// 63 | /// All table elements are allocated uninitialized. 64 | /// 65 | /// # Errors 66 | /// 67 | /// Returns `Err` if `initial_size` is greater than `maximum_size`. 68 | pub fn alloc(initial_size: u32, maximum_size: Option) -> Result { 69 | let table = TableInstance::new(ResizableLimits::new(initial_size, maximum_size))?; 70 | Ok(TableRef(Rc::new(table))) 71 | } 72 | 73 | fn new(limits: ResizableLimits) -> Result { 74 | check_limits(&limits)?; 75 | Ok(TableInstance { 76 | buffer: RefCell::new(vec![None; limits.initial() as usize]), 77 | limits: limits, 78 | }) 79 | } 80 | 81 | /// Return table limits. 82 | pub(crate) fn limits(&self) -> &ResizableLimits { 83 | &self.limits 84 | } 85 | 86 | /// Returns size this table was created with. 87 | pub fn initial_size(&self) -> u32 { 88 | self.limits.initial() 89 | } 90 | 91 | /// Returns maximum size `TableInstance` can grow to. 92 | pub fn maximum_size(&self) -> Option { 93 | self.limits.maximum() 94 | } 95 | 96 | /// Returns current size of the table. 97 | pub fn current_size(&self) -> u32 { 98 | self.buffer.borrow().len() as u32 99 | } 100 | 101 | /// Increases the size of the table by given number of elements. 102 | /// 103 | /// # Errors 104 | /// 105 | /// Returns `Err` if tried to allocate more elements than permited by limit. 106 | pub fn grow(&self, by: u32) -> Result<(), Error> { 107 | let mut buffer = self.buffer.borrow_mut(); 108 | let maximum_size = self.maximum_size().unwrap_or(u32::MAX); 109 | let new_size = self 110 | .current_size() 111 | .checked_add(by) 112 | .and_then(|new_size| { 113 | if maximum_size < new_size { 114 | None 115 | } else { 116 | Some(new_size) 117 | } 118 | }) 119 | .ok_or_else(|| { 120 | Error::Table(format!( 121 | "Trying to grow table by {} items when there are already {} items", 122 | by, 123 | self.current_size(), 124 | )) 125 | })?; 126 | buffer.resize(new_size as usize, None); 127 | Ok(()) 128 | } 129 | 130 | /// Get the specific value in the table 131 | pub fn get(&self, offset: u32) -> Result, Error> { 132 | let buffer = self.buffer.borrow(); 133 | let buffer_len = buffer.len(); 134 | let table_elem = buffer.get(offset as usize).cloned().ok_or_else(|| { 135 | Error::Table(format!( 136 | "trying to read table item with index {} when there are only {} items", 137 | offset, buffer_len 138 | )) 139 | })?; 140 | Ok(table_elem) 141 | } 142 | 143 | /// Set the table element to the specified function. 144 | pub fn set(&self, offset: u32, value: Option) -> Result<(), Error> { 145 | let mut buffer = self.buffer.borrow_mut(); 146 | let buffer_len = buffer.len(); 147 | let table_elem = buffer.get_mut(offset as usize).ok_or_else(|| { 148 | Error::Table(format!( 149 | "trying to update table item with index {} when there are only {} items", 150 | offset, buffer_len 151 | )) 152 | })?; 153 | *table_elem = value; 154 | Ok(()) 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /vendor/wasmi/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | use wabt; 2 | use Module; 3 | 4 | mod host; 5 | mod wasm; 6 | 7 | use super::Error; 8 | 9 | fn assert_send() {} 10 | fn assert_sync() {} 11 | fn assert_std_err_impl() {} 12 | 13 | #[test] 14 | fn assert_error_properties() { 15 | assert_send::(); 16 | assert_sync::(); 17 | assert_std_err_impl::(); 18 | } 19 | 20 | /// Test that converting an u32 (u64) that does not fit in an i32 (i64) 21 | /// to a RuntimeValue and back works as expected and the number remains unchanged. 22 | #[test] 23 | fn unsigned_to_runtime_value() { 24 | use super::RuntimeValue; 25 | 26 | let overflow_i32: u32 = ::core::i32::MAX as u32 + 1; 27 | assert_eq!( 28 | RuntimeValue::from(overflow_i32).try_into::().unwrap(), 29 | overflow_i32 30 | ); 31 | 32 | let overflow_i64: u64 = ::core::i64::MAX as u64 + 1; 33 | assert_eq!( 34 | RuntimeValue::from(overflow_i64).try_into::().unwrap(), 35 | overflow_i64 36 | ); 37 | } 38 | 39 | pub fn parse_wat(source: &str) -> Module { 40 | let wasm_binary = wabt::wat2wasm(source).expect("Failed to parse wat source"); 41 | Module::from_buffer(wasm_binary).expect("Failed to load parsed module") 42 | } 43 | -------------------------------------------------------------------------------- /vendor/wasmi/src/tests/wasm.rs: -------------------------------------------------------------------------------- 1 | use memory_units::Pages; 2 | use std::fs::File; 3 | use { 4 | Error, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef, ImportsBuilder, MemoryDescriptor, 5 | MemoryInstance, MemoryRef, Module, ModuleImportResolver, ModuleInstance, NopExternals, 6 | RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef, 7 | }; 8 | 9 | struct Env { 10 | table_base: GlobalRef, 11 | memory_base: GlobalRef, 12 | memory: MemoryRef, 13 | table: TableRef, 14 | } 15 | 16 | impl Env { 17 | fn new() -> Env { 18 | Env { 19 | table_base: GlobalInstance::alloc(RuntimeValue::I32(0), false), 20 | memory_base: GlobalInstance::alloc(RuntimeValue::I32(0), false), 21 | memory: MemoryInstance::alloc(Pages(256), None).unwrap(), 22 | table: TableInstance::alloc(64, None).unwrap(), 23 | } 24 | } 25 | } 26 | 27 | impl ModuleImportResolver for Env { 28 | fn resolve_func(&self, _field_name: &str, _func_type: &Signature) -> Result { 29 | Err(Error::Instantiation( 30 | "env module doesn't provide any functions".into(), 31 | )) 32 | } 33 | 34 | fn resolve_global( 35 | &self, 36 | field_name: &str, 37 | _global_type: &GlobalDescriptor, 38 | ) -> Result { 39 | match field_name { 40 | "tableBase" => Ok(self.table_base.clone()), 41 | "memoryBase" => Ok(self.memory_base.clone()), 42 | _ => Err(Error::Instantiation(format!( 43 | "env module doesn't provide global '{}'", 44 | field_name 45 | ))), 46 | } 47 | } 48 | 49 | fn resolve_memory( 50 | &self, 51 | field_name: &str, 52 | _memory_type: &MemoryDescriptor, 53 | ) -> Result { 54 | match field_name { 55 | "memory" => Ok(self.memory.clone()), 56 | _ => Err(Error::Instantiation(format!( 57 | "env module doesn't provide memory '{}'", 58 | field_name 59 | ))), 60 | } 61 | } 62 | 63 | fn resolve_table( 64 | &self, 65 | field_name: &str, 66 | _table_type: &TableDescriptor, 67 | ) -> Result { 68 | match field_name { 69 | "table" => Ok(self.table.clone()), 70 | _ => Err(Error::Instantiation(format!( 71 | "env module doesn't provide table '{}'", 72 | field_name 73 | ))), 74 | } 75 | } 76 | } 77 | 78 | fn load_from_file(filename: &str) -> Module { 79 | use std::io::prelude::*; 80 | let mut file = File::open(filename).unwrap(); 81 | let mut buf = Vec::new(); 82 | file.read_to_end(&mut buf).unwrap(); 83 | let wasm_buf = ::wabt::wat2wasm(&buf).unwrap(); 84 | Module::from_buffer(wasm_buf).unwrap() 85 | } 86 | 87 | #[test] 88 | fn interpreter_inc_i32() { 89 | // Name of function contained in WASM file (note the leading underline) 90 | const FUNCTION_NAME: &'static str = "_inc_i32"; 91 | // The WASM file containing the module and function 92 | const WASM_FILE: &str = &"res/fixtures/inc_i32.wast"; 93 | 94 | let module = load_from_file(WASM_FILE); 95 | 96 | let env = Env::new(); 97 | 98 | let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) 99 | .expect("Failed to instantiate module") 100 | .assert_no_start(); 101 | 102 | let i32_val = 42; 103 | // the functions expects a single i32 parameter 104 | let args = &[RuntimeValue::I32(i32_val)]; 105 | let exp_retval = Some(RuntimeValue::I32(i32_val + 1)); 106 | 107 | let retval = instance 108 | .invoke_export(FUNCTION_NAME, args, &mut NopExternals) 109 | .expect(""); 110 | assert_eq!(exp_retval, retval); 111 | } 112 | 113 | #[test] 114 | fn interpreter_accumulate_u8() { 115 | // Name of function contained in WASM file (note the leading underline) 116 | const FUNCTION_NAME: &'static str = "_accumulate_u8"; 117 | // The WASM file containing the module and function 118 | const WASM_FILE: &str = &"res/fixtures/accumulate_u8.wast"; 119 | // The octet sequence being accumulated 120 | const BUF: &[u8] = &[9, 8, 7, 6, 5, 4, 3, 2, 1]; 121 | 122 | // Load the module-structure from wasm-file and add to program 123 | let module = load_from_file(WASM_FILE); 124 | 125 | let env = Env::new(); 126 | let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) 127 | .expect("Failed to instantiate module") 128 | .assert_no_start(); 129 | 130 | let env_memory = env.memory.clone(); 131 | 132 | // Place the octet-sequence at index 0 in linear memory 133 | let offset: u32 = 0; 134 | let _ = env_memory.set(offset, BUF); 135 | 136 | // Set up the function argument list and invoke the function 137 | let args = &[ 138 | RuntimeValue::I32(BUF.len() as i32), 139 | RuntimeValue::I32(offset as i32), 140 | ]; 141 | let retval = instance 142 | .invoke_export(FUNCTION_NAME, args, &mut NopExternals) 143 | .expect("Failed to execute function"); 144 | 145 | // For verification, repeat accumulation using native code 146 | let accu = BUF.into_iter().fold(0 as i32, |a, b| a + *b as i32); 147 | let exp_retval: Option = Some(RuntimeValue::I32(accu)); 148 | 149 | // Verify calculation from WebAssembly runtime is identical to expected result 150 | assert_eq!(exp_retval, retval); 151 | } 152 | -------------------------------------------------------------------------------- /vendor/wasmi/src/types.rs: -------------------------------------------------------------------------------- 1 | use alloc::borrow::Cow; 2 | 3 | use parity_wasm::elements::{ 4 | FunctionType, GlobalType, MemoryType, TableType, ValueType as EValueType, 5 | }; 6 | 7 | /// Signature of a [function]. 8 | /// 9 | /// Signature of a function consists of zero or more parameter [types][type] and zero or one return [type]. 10 | /// 11 | /// Two signatures are considered equal if they have equal list of parameters and equal return types. 12 | /// 13 | /// [type]: enum.ValueType.html 14 | /// [function]: struct.FuncInstance.html 15 | #[derive(Debug, Clone, PartialEq, Eq)] 16 | pub struct Signature { 17 | params: Cow<'static, [ValueType]>, 18 | return_type: Option, 19 | } 20 | 21 | impl Signature { 22 | /// Creates new signature with givens 23 | /// parameter types and optional return type. 24 | /// 25 | /// # Examples 26 | /// 27 | /// ```rust 28 | /// use wasmi::{Signature, ValueType}; 29 | /// 30 | /// // s1: (i32) -> () 31 | /// let s1 = Signature::new(&[ValueType::I32][..], None); 32 | /// 33 | /// // s2: () -> i32 34 | /// let s2 = Signature::new(&[][..], Some(ValueType::I32)); 35 | /// 36 | /// // s3: (I64) -> () 37 | /// let dynamic_params = vec![ValueType::I64]; 38 | /// let s3 = Signature::new(dynamic_params, None); 39 | /// ``` 40 | pub fn new>>( 41 | params: C, 42 | return_type: Option, 43 | ) -> Signature { 44 | Signature { 45 | params: params.into(), 46 | return_type: return_type, 47 | } 48 | } 49 | 50 | /// Returns parameter types of this signature. 51 | pub fn params(&self) -> &[ValueType] { 52 | &self.params.as_ref() 53 | } 54 | 55 | /// Returns return type of this signature. 56 | pub fn return_type(&self) -> Option { 57 | self.return_type 58 | } 59 | 60 | pub(crate) fn from_elements(func_type: &FunctionType) -> Signature { 61 | Signature { 62 | params: func_type 63 | .params() 64 | .iter() 65 | .cloned() 66 | .map(ValueType::from_elements) 67 | .collect(), 68 | return_type: func_type.return_type().map(ValueType::from_elements), 69 | } 70 | } 71 | } 72 | 73 | /// Type of a value. 74 | /// 75 | /// See [`RuntimeValue`] for details. 76 | /// 77 | /// [`RuntimeValue`]: enum.RuntimeValue.html 78 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 79 | pub enum ValueType { 80 | /// 32-bit signed or unsigned integer. 81 | I32, 82 | /// 64-bit signed or unsigned integer. 83 | I64, 84 | /// 32-bit IEEE 754-2008 floating point number. 85 | F32, 86 | /// 64-bit IEEE 754-2008 floating point number. 87 | F64, 88 | } 89 | 90 | impl ValueType { 91 | pub(crate) fn from_elements(value_type: EValueType) -> ValueType { 92 | match value_type { 93 | EValueType::I32 => ValueType::I32, 94 | EValueType::I64 => ValueType::I64, 95 | EValueType::F32 => ValueType::F32, 96 | EValueType::F64 => ValueType::F64, 97 | } 98 | } 99 | 100 | pub(crate) fn into_elements(self) -> EValueType { 101 | match self { 102 | ValueType::I32 => EValueType::I32, 103 | ValueType::I64 => EValueType::I64, 104 | ValueType::F32 => EValueType::F32, 105 | ValueType::F64 => EValueType::F64, 106 | } 107 | } 108 | } 109 | 110 | /// Description of a global variable. 111 | /// 112 | /// Primarly used to describe imports of global variables. 113 | /// See [`ImportResolver`] for details. 114 | /// 115 | /// [`ImportResolver`]: trait.ImportResolver.html 116 | pub struct GlobalDescriptor { 117 | value_type: ValueType, 118 | mutable: bool, 119 | } 120 | 121 | impl GlobalDescriptor { 122 | pub(crate) fn from_elements(global_type: &GlobalType) -> GlobalDescriptor { 123 | GlobalDescriptor { 124 | value_type: ValueType::from_elements(global_type.content_type()), 125 | mutable: global_type.is_mutable(), 126 | } 127 | } 128 | 129 | /// Returns [`ValueType`] of the requested global. 130 | /// 131 | /// [`ValueType`]: enum.ValueType.html 132 | pub fn value_type(&self) -> ValueType { 133 | self.value_type 134 | } 135 | 136 | /// Returns whether the requested global mutable. 137 | pub fn is_mutable(&self) -> bool { 138 | self.mutable 139 | } 140 | } 141 | 142 | /// Description of a table. 143 | /// 144 | /// Primarly used to describe imports of tables. 145 | /// See [`ImportResolver`] for details. 146 | /// 147 | /// [`ImportResolver`]: trait.ImportResolver.html 148 | pub struct TableDescriptor { 149 | initial: u32, 150 | maximum: Option, 151 | } 152 | 153 | impl TableDescriptor { 154 | pub(crate) fn from_elements(table_type: &TableType) -> TableDescriptor { 155 | TableDescriptor { 156 | initial: table_type.limits().initial(), 157 | maximum: table_type.limits().maximum(), 158 | } 159 | } 160 | 161 | /// Returns initial size of the requested table. 162 | pub fn initial(&self) -> u32 { 163 | self.initial 164 | } 165 | 166 | /// Returns maximum size of the requested table. 167 | pub fn maximum(&self) -> Option { 168 | self.maximum 169 | } 170 | } 171 | 172 | /// Description of a linear memory. 173 | /// 174 | /// Primarly used to describe imports of linear memories. 175 | /// See [`ImportResolver`] for details. 176 | /// 177 | /// [`ImportResolver`]: trait.ImportResolver.html 178 | pub struct MemoryDescriptor { 179 | initial: u32, 180 | maximum: Option, 181 | } 182 | 183 | impl MemoryDescriptor { 184 | pub(crate) fn from_elements(memory_type: &MemoryType) -> MemoryDescriptor { 185 | MemoryDescriptor { 186 | initial: memory_type.limits().initial(), 187 | maximum: memory_type.limits().maximum(), 188 | } 189 | } 190 | 191 | /// Returns initial size (in pages) of the requested memory. 192 | pub fn initial(&self) -> u32 { 193 | self.initial 194 | } 195 | 196 | /// Returns maximum size (in pages) of the requested memory. 197 | pub fn maximum(&self) -> Option { 198 | self.maximum 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /vendor/wasmi/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | cd $(dirname $0) 6 | 7 | time cargo test --all 8 | 9 | cd - 10 | -------------------------------------------------------------------------------- /vendor/wasmi/tests/spec/mod.rs: -------------------------------------------------------------------------------- 1 | mod run; 2 | 3 | macro_rules! run_test { 4 | ($label: expr, $test_name: ident) => { 5 | #[test] 6 | fn $test_name() { 7 | self::run::spec($label) 8 | } 9 | }; 10 | } 11 | 12 | run_test!("address", wasm_address); 13 | run_test!("align", wasm_align); 14 | run_test!("binary", wasm_binary); 15 | run_test!("block", wasm_block); 16 | run_test!("br", wasm_br); 17 | run_test!("br_if", wasm_br_if); 18 | run_test!("br_table", wasm_br_table); 19 | run_test!("break-drop", wasm_break_drop); 20 | run_test!("call", wasm_call); 21 | run_test!("call_indirect", wasm_call_indirect); 22 | run_test!("comments", wasm_comments); 23 | run_test!("const", wasm_const); 24 | run_test!("conversions", wasm_conversions); 25 | run_test!("custom", wasm_custom); 26 | run_test!("custom_section", wasm_custom_section); 27 | run_test!("data", wasm_data); 28 | run_test!("elem", wasm_elem); 29 | run_test!("endianness", wasm_endianness); 30 | run_test!("exports", wasm_exports); 31 | run_test!("f32", wasm_f32); 32 | run_test!("f32_bitwise", wasm_f32_bitwise); 33 | run_test!("f32_cmp", wasm_f32_cmp); 34 | run_test!("f64", wasm_f64); 35 | run_test!("f64_bitwise", wasm_f64_bitwise); 36 | run_test!("f64_cmp", wasm_f64_cmp); 37 | run_test!("fac", wasm_fac); 38 | run_test!("float_exprs", wasm_float_exprs); 39 | run_test!("float_literals", wasm_float_literals); 40 | run_test!("float_memory", wasm_float_memory); 41 | run_test!("float_misc", wasm_float_misc); 42 | run_test!("forward", wasm_forward); 43 | run_test!("func", wasm_func); 44 | run_test!("func_ptrs", wasm_func_ptrs); 45 | run_test!("get_local", wasm_get_local); 46 | run_test!("globals", wasm_globals); 47 | run_test!("i32", wasm_i32); 48 | run_test!("i64", wasm_i64); 49 | run_test!("if", wasm_if); 50 | run_test!("imports", wasm_imports); 51 | run_test!("inline-module", inline_module); 52 | run_test!("int_exprs", wasm_int_exprs); 53 | run_test!("int_literals", wasm_int_literals); 54 | run_test!("labels", wasm_labels); 55 | run_test!("left-to-right", wasm_left_to_right); 56 | run_test!("linking", wasm_linking); 57 | run_test!("loop", wasm_loop); 58 | run_test!("memory", wasm_memory); 59 | run_test!("memory_redundancy", wasm_memory_redundancy); 60 | run_test!("memory_trap", wasm_memory_trap); 61 | run_test!("names", wasm_names); 62 | run_test!("nop", wasm_nop); 63 | run_test!("resizing", wasm_resizing); 64 | run_test!("return", wasm_return); 65 | run_test!("select", wasm_select); 66 | run_test!("set_local", wasm_set_local); 67 | run_test!("skip-stack-guard-page", wasm_skip_stack_guard_page); 68 | run_test!("stack", wasm_stack); 69 | run_test!("start", wasm_start); 70 | run_test!("store_retval", wasm_store_retval); 71 | run_test!("switch", wasm_switch); 72 | run_test!("tee_local", wasm_tee_local); 73 | run_test!("token", wasm_token); 74 | run_test!("traps", wasm_traps); 75 | run_test!("type", wasm_type); 76 | run_test!("typecheck", wasm_typecheck); 77 | run_test!("unreachable", wasm_unreachable); 78 | run_test!("unreached-invalid", wasm_unreached_invalid); 79 | run_test!("unwind", wasm_unwind); 80 | run_test!("utf8-custom-section-id", wasm_utf8_custom_section_id); 81 | run_test!("utf8-import-field", wasm_utf8_import_field); 82 | run_test!("utf8-import-module", wasm_utf8_import_module); 83 | run_test!("utf8-invalid-encoding", wasm_utf8_invalid_encoding); 84 | -------------------------------------------------------------------------------- /vendor/wasmi/tests/spec_shim.rs: -------------------------------------------------------------------------------- 1 | //! Official spec testsuite. 2 | 3 | extern crate wabt; 4 | extern crate wasmi; 5 | 6 | mod spec; 7 | -------------------------------------------------------------------------------- /vendor/wasmi/validation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasmi-validation" 3 | version = "0.1.0" 4 | authors = ["Parity Technologies "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | parity-wasm = { version = "0.31", default-features = false } 9 | hashbrown = { version = "0.1.8", optional = true } 10 | 11 | [dev-dependencies] 12 | assert_matches = "1.1" 13 | 14 | [features] 15 | default = ["std"] 16 | std = ["parity-wasm/std"] 17 | core = [ 18 | "hashbrown/nightly" 19 | ] 20 | -------------------------------------------------------------------------------- /vendor/wasmi/validation/src/context.rs: -------------------------------------------------------------------------------- 1 | use crate::Error; 2 | #[allow(unused_imports)] 3 | use alloc::prelude::v1::*; 4 | use parity_wasm::elements::{ 5 | BlockType, FunctionType, GlobalType, MemoryType, TableType, ValueType, 6 | }; 7 | 8 | #[derive(Default, Debug)] 9 | pub struct ModuleContext { 10 | pub memories: Vec, 11 | pub tables: Vec, 12 | pub globals: Vec, 13 | pub types: Vec, 14 | pub func_type_indexes: Vec, 15 | } 16 | 17 | impl ModuleContext { 18 | pub fn memories(&self) -> &[MemoryType] { 19 | &self.memories 20 | } 21 | 22 | pub fn tables(&self) -> &[TableType] { 23 | &self.tables 24 | } 25 | 26 | pub fn globals(&self) -> &[GlobalType] { 27 | &self.globals 28 | } 29 | 30 | pub fn types(&self) -> &[FunctionType] { 31 | &self.types 32 | } 33 | 34 | pub fn func_type_indexes(&self) -> &[u32] { 35 | &self.func_type_indexes 36 | } 37 | 38 | pub fn require_memory(&self, idx: u32) -> Result<(), Error> { 39 | if self.memories().get(idx as usize).is_none() { 40 | return Err(Error(format!("Memory at index {} doesn't exists", idx))); 41 | } 42 | Ok(()) 43 | } 44 | 45 | pub fn require_table(&self, idx: u32) -> Result<&TableType, Error> { 46 | self.tables() 47 | .get(idx as usize) 48 | .ok_or_else(|| Error(format!("Table at index {} doesn't exists", idx))) 49 | } 50 | 51 | pub fn require_function(&self, idx: u32) -> Result<(&[ValueType], BlockType), Error> { 52 | let ty_idx = self 53 | .func_type_indexes() 54 | .get(idx as usize) 55 | .ok_or_else(|| Error(format!("Function at index {} doesn't exists", idx)))?; 56 | self.require_function_type(*ty_idx) 57 | } 58 | 59 | pub fn require_function_type(&self, idx: u32) -> Result<(&[ValueType], BlockType), Error> { 60 | let ty = self 61 | .types() 62 | .get(idx as usize) 63 | .ok_or_else(|| Error(format!("Type at index {} doesn't exists", idx)))?; 64 | 65 | let params = ty.params(); 66 | let return_ty = ty 67 | .return_type() 68 | .map(BlockType::Value) 69 | .unwrap_or(BlockType::NoResult); 70 | Ok((params, return_ty)) 71 | } 72 | 73 | pub fn require_global(&self, idx: u32, mutability: Option) -> Result<&GlobalType, Error> { 74 | let global = self 75 | .globals() 76 | .get(idx as usize) 77 | .ok_or_else(|| Error(format!("Global at index {} doesn't exists", idx)))?; 78 | 79 | if let Some(expected_mutable) = mutability { 80 | if expected_mutable && !global.is_mutable() { 81 | return Err(Error(format!("Expected global {} to be mutable", idx))); 82 | } 83 | if !expected_mutable && global.is_mutable() { 84 | return Err(Error(format!("Expected global {} to be immutable", idx))); 85 | } 86 | } 87 | Ok(global) 88 | } 89 | } 90 | 91 | #[derive(Default)] 92 | pub struct ModuleContextBuilder { 93 | memories: Vec, 94 | tables: Vec, 95 | globals: Vec, 96 | types: Vec, 97 | func_type_indexes: Vec, 98 | } 99 | 100 | impl ModuleContextBuilder { 101 | pub fn new() -> ModuleContextBuilder { 102 | ModuleContextBuilder::default() 103 | } 104 | 105 | pub fn push_memory(&mut self, memory: MemoryType) { 106 | self.memories.push(memory); 107 | } 108 | 109 | pub fn push_table(&mut self, table: TableType) { 110 | self.tables.push(table); 111 | } 112 | 113 | pub fn push_global(&mut self, global: GlobalType) { 114 | self.globals.push(global); 115 | } 116 | 117 | pub fn set_types(&mut self, types: Vec) { 118 | self.types = types; 119 | } 120 | 121 | pub fn push_func_type_index(&mut self, func_type_index: u32) { 122 | self.func_type_indexes.push(func_type_index); 123 | } 124 | 125 | pub fn build(self) -> ModuleContext { 126 | let ModuleContextBuilder { 127 | memories, 128 | tables, 129 | globals, 130 | types, 131 | func_type_indexes, 132 | } = self; 133 | 134 | ModuleContext { 135 | memories, 136 | tables, 137 | globals, 138 | types, 139 | func_type_indexes, 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /vendor/wasmi/validation/src/stack.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports)] 2 | use alloc::prelude::v1::*; 3 | 4 | use core::fmt; 5 | #[cfg(feature = "std")] 6 | use std::error; 7 | 8 | #[derive(Debug)] 9 | pub struct Error(String); 10 | 11 | impl fmt::Display for Error { 12 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 13 | write!(f, "{}", self.0) 14 | } 15 | } 16 | 17 | #[cfg(feature = "std")] 18 | impl error::Error for Error { 19 | fn description(&self) -> &str { 20 | &self.0 21 | } 22 | } 23 | 24 | /// Stack with limit. 25 | #[derive(Debug)] 26 | pub struct StackWithLimit 27 | where 28 | T: Clone, 29 | { 30 | /// Stack values. 31 | values: Vec, 32 | /// Stack limit (maximal stack len). 33 | limit: usize, 34 | } 35 | 36 | impl StackWithLimit 37 | where 38 | T: Clone, 39 | { 40 | pub fn with_limit(limit: usize) -> Self { 41 | StackWithLimit { 42 | values: Vec::new(), 43 | limit: limit, 44 | } 45 | } 46 | 47 | pub fn is_empty(&self) -> bool { 48 | self.values.is_empty() 49 | } 50 | 51 | pub fn len(&self) -> usize { 52 | self.values.len() 53 | } 54 | 55 | pub fn top(&self) -> Result<&T, Error> { 56 | self.values 57 | .last() 58 | .ok_or_else(|| Error("non-empty stack expected".into())) 59 | } 60 | 61 | pub fn top_mut(&mut self) -> Result<&mut T, Error> { 62 | self.values 63 | .last_mut() 64 | .ok_or_else(|| Error("non-empty stack expected".into())) 65 | } 66 | 67 | pub fn get(&self, index: usize) -> Result<&T, Error> { 68 | if index >= self.values.len() { 69 | return Err(Error(format!( 70 | "trying to get value at position {} on stack of size {}", 71 | index, 72 | self.values.len() 73 | ))); 74 | } 75 | 76 | Ok(self 77 | .values 78 | .get(self.values.len() - 1 - index) 79 | .expect("checked couple of lines above")) 80 | } 81 | 82 | pub fn push(&mut self, value: T) -> Result<(), Error> { 83 | if self.values.len() >= self.limit { 84 | return Err(Error(format!("exceeded stack limit {}", self.limit))); 85 | } 86 | 87 | self.values.push(value); 88 | Ok(()) 89 | } 90 | 91 | pub fn pop(&mut self) -> Result { 92 | self.values 93 | .pop() 94 | .ok_or_else(|| Error("non-empty stack expected".into())) 95 | } 96 | 97 | pub fn resize(&mut self, new_size: usize, dummy: T) { 98 | debug_assert!(new_size <= self.values.len()); 99 | self.values.resize(new_size, dummy); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /vendor/wasmi/validation/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{Error, PlainValidator}; 2 | use parity_wasm::{ 3 | builder::module, 4 | elements::{ 5 | BlockType, External, GlobalEntry, GlobalType, ImportEntry, InitExpr, Instruction, 6 | Instructions, MemoryType, Module, TableType, ValueType, 7 | }, 8 | }; 9 | 10 | fn validate_module(module: &Module) -> Result<(), Error> { 11 | super::validate_module::(module) 12 | } 13 | 14 | #[test] 15 | fn empty_is_valid() { 16 | let module = module().build(); 17 | assert!(validate_module(&module).is_ok()); 18 | } 19 | 20 | #[test] 21 | fn limits() { 22 | let test_cases = vec![ 23 | // min > max 24 | (10, Some(9), false), 25 | // min = max 26 | (10, Some(10), true), 27 | // table/memory is always valid without max 28 | (10, None, true), 29 | ]; 30 | 31 | for (min, max, is_valid) in test_cases { 32 | // defined table 33 | let m = module().table().with_min(min).with_max(max).build().build(); 34 | assert_eq!(validate_module(&m).is_ok(), is_valid); 35 | 36 | // imported table 37 | let m = module() 38 | .with_import(ImportEntry::new( 39 | "core".into(), 40 | "table".into(), 41 | External::Table(TableType::new(min, max)), 42 | )) 43 | .build(); 44 | assert_eq!(validate_module(&m).is_ok(), is_valid); 45 | 46 | // defined memory 47 | let m = module() 48 | .memory() 49 | .with_min(min) 50 | .with_max(max) 51 | .build() 52 | .build(); 53 | assert_eq!(validate_module(&m).is_ok(), is_valid); 54 | 55 | // imported table 56 | let m = module() 57 | .with_import(ImportEntry::new( 58 | "core".into(), 59 | "memory".into(), 60 | External::Memory(MemoryType::new(min, max)), 61 | )) 62 | .build(); 63 | assert_eq!(validate_module(&m).is_ok(), is_valid); 64 | } 65 | } 66 | 67 | #[test] 68 | fn global_init_const() { 69 | let m = module() 70 | .with_global(GlobalEntry::new( 71 | GlobalType::new(ValueType::I32, true), 72 | InitExpr::new(vec![Instruction::I32Const(42), Instruction::End]), 73 | )) 74 | .build(); 75 | assert!(validate_module(&m).is_ok()); 76 | 77 | // init expr type differs from declared global type 78 | let m = module() 79 | .with_global(GlobalEntry::new( 80 | GlobalType::new(ValueType::I64, true), 81 | InitExpr::new(vec![Instruction::I32Const(42), Instruction::End]), 82 | )) 83 | .build(); 84 | assert!(validate_module(&m).is_err()); 85 | } 86 | 87 | #[test] 88 | fn global_init_global() { 89 | let m = module() 90 | .with_import(ImportEntry::new( 91 | "env".into(), 92 | "ext_global".into(), 93 | External::Global(GlobalType::new(ValueType::I32, false)), 94 | )) 95 | .with_global(GlobalEntry::new( 96 | GlobalType::new(ValueType::I32, true), 97 | InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), 98 | )) 99 | .build(); 100 | assert!(validate_module(&m).is_ok()); 101 | 102 | // get_global can reference only previously defined globals 103 | let m = module() 104 | .with_global(GlobalEntry::new( 105 | GlobalType::new(ValueType::I32, true), 106 | InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), 107 | )) 108 | .build(); 109 | assert!(validate_module(&m).is_err()); 110 | 111 | // get_global can reference only const globals 112 | let m = module() 113 | .with_import(ImportEntry::new( 114 | "env".into(), 115 | "ext_global".into(), 116 | External::Global(GlobalType::new(ValueType::I32, true)), 117 | )) 118 | .with_global(GlobalEntry::new( 119 | GlobalType::new(ValueType::I32, true), 120 | InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), 121 | )) 122 | .build(); 123 | assert!(validate_module(&m).is_err()); 124 | 125 | // get_global in init_expr can only refer to imported globals. 126 | let m = module() 127 | .with_global(GlobalEntry::new( 128 | GlobalType::new(ValueType::I32, false), 129 | InitExpr::new(vec![Instruction::I32Const(0), Instruction::End]), 130 | )) 131 | .with_global(GlobalEntry::new( 132 | GlobalType::new(ValueType::I32, true), 133 | InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), 134 | )) 135 | .build(); 136 | assert!(validate_module(&m).is_err()); 137 | } 138 | 139 | #[test] 140 | fn global_init_misc() { 141 | // without delimiting End opcode 142 | let m = module() 143 | .with_global(GlobalEntry::new( 144 | GlobalType::new(ValueType::I32, true), 145 | InitExpr::new(vec![Instruction::I32Const(42)]), 146 | )) 147 | .build(); 148 | assert!(validate_module(&m).is_err()); 149 | 150 | // empty init expr 151 | let m = module() 152 | .with_global(GlobalEntry::new( 153 | GlobalType::new(ValueType::I32, true), 154 | InitExpr::new(vec![Instruction::End]), 155 | )) 156 | .build(); 157 | assert!(validate_module(&m).is_err()); 158 | 159 | // not an constant opcode used 160 | let m = module() 161 | .with_global(GlobalEntry::new( 162 | GlobalType::new(ValueType::I32, true), 163 | InitExpr::new(vec![Instruction::Unreachable, Instruction::End]), 164 | )) 165 | .build(); 166 | assert!(validate_module(&m).is_err()); 167 | } 168 | 169 | #[test] 170 | fn module_limits_validity() { 171 | // module cannot contain more than 1 memory atm. 172 | let m = module() 173 | .with_import(ImportEntry::new( 174 | "core".into(), 175 | "memory".into(), 176 | External::Memory(MemoryType::new(10, None)), 177 | )) 178 | .memory() 179 | .with_min(10) 180 | .build() 181 | .build(); 182 | assert!(validate_module(&m).is_err()); 183 | 184 | // module cannot contain more than 1 table atm. 185 | let m = module() 186 | .with_import(ImportEntry::new( 187 | "core".into(), 188 | "table".into(), 189 | External::Table(TableType::new(10, None)), 190 | )) 191 | .table() 192 | .with_min(10) 193 | .build() 194 | .build(); 195 | assert!(validate_module(&m).is_err()); 196 | } 197 | 198 | #[test] 199 | fn funcs() { 200 | // recursive function calls is legal. 201 | let m = module() 202 | .function() 203 | .signature() 204 | .return_type() 205 | .i32() 206 | .build() 207 | .body() 208 | .with_instructions(Instructions::new(vec![ 209 | Instruction::Call(1), 210 | Instruction::End, 211 | ])) 212 | .build() 213 | .build() 214 | .function() 215 | .signature() 216 | .return_type() 217 | .i32() 218 | .build() 219 | .body() 220 | .with_instructions(Instructions::new(vec![ 221 | Instruction::Call(0), 222 | Instruction::End, 223 | ])) 224 | .build() 225 | .build() 226 | .build(); 227 | assert!(validate_module(&m).is_ok()); 228 | } 229 | 230 | #[test] 231 | fn globals() { 232 | // import immutable global is legal. 233 | let m = module() 234 | .with_import(ImportEntry::new( 235 | "env".into(), 236 | "ext_global".into(), 237 | External::Global(GlobalType::new(ValueType::I32, false)), 238 | )) 239 | .build(); 240 | assert!(validate_module(&m).is_ok()); 241 | 242 | // import mutable global is invalid. 243 | let m = module() 244 | .with_import(ImportEntry::new( 245 | "env".into(), 246 | "ext_global".into(), 247 | External::Global(GlobalType::new(ValueType::I32, true)), 248 | )) 249 | .build(); 250 | assert!(validate_module(&m).is_err()); 251 | } 252 | 253 | #[test] 254 | fn if_else_with_return_type_validation() { 255 | let m = module() 256 | .function() 257 | .signature() 258 | .build() 259 | .body() 260 | .with_instructions(Instructions::new(vec![ 261 | Instruction::I32Const(1), 262 | Instruction::If(BlockType::NoResult), 263 | Instruction::I32Const(1), 264 | Instruction::If(BlockType::Value(ValueType::I32)), 265 | Instruction::I32Const(1), 266 | Instruction::Else, 267 | Instruction::I32Const(2), 268 | Instruction::End, 269 | Instruction::Drop, 270 | Instruction::End, 271 | Instruction::End, 272 | ])) 273 | .build() 274 | .build() 275 | .build(); 276 | validate_module(&m).unwrap(); 277 | } 278 | -------------------------------------------------------------------------------- /vendor/wasmi/validation/src/util.rs: -------------------------------------------------------------------------------- 1 | use crate::Error; 2 | #[allow(unused_imports)] 3 | use alloc::prelude::v1::*; 4 | use parity_wasm::elements::{Local, ValueType}; 5 | 6 | #[cfg(test)] 7 | use assert_matches::assert_matches; 8 | 9 | /// Locals are the concatenation of a slice of function parameters 10 | /// with function declared local variables. 11 | /// 12 | /// Local variables are given in the form of groups represented by pairs 13 | /// of a value_type and a count. 14 | #[derive(Debug)] 15 | pub struct Locals<'a> { 16 | params: &'a [ValueType], 17 | local_groups: &'a [Local], 18 | count: u32, 19 | } 20 | 21 | impl<'a> Locals<'a> { 22 | /// Create a new wrapper around declared variables and parameters. 23 | pub fn new(params: &'a [ValueType], local_groups: &'a [Local]) -> Result, Error> { 24 | let mut acc = params.len() as u32; 25 | for locals_group in local_groups { 26 | acc = acc 27 | .checked_add(locals_group.count()) 28 | .ok_or_else(|| Error(String::from("Locals range not in 32-bit range")))?; 29 | } 30 | 31 | Ok(Locals { 32 | params, 33 | local_groups, 34 | count: acc, 35 | }) 36 | } 37 | 38 | /// Returns parameter count. 39 | pub fn param_count(&self) -> u32 { 40 | self.params.len() as u32 41 | } 42 | 43 | /// Returns total count of all declared locals and paramaterers. 44 | pub fn count(&self) -> u32 { 45 | self.count 46 | } 47 | 48 | /// Returns the type of a local variable (either a declared local or a param). 49 | /// 50 | /// Returns `Err` in the case of overflow or when idx falls out of range. 51 | pub fn type_of_local(&self, idx: u32) -> Result { 52 | if let Some(param) = self.params.get(idx as usize) { 53 | return Ok(*param); 54 | } 55 | 56 | // If an index doesn't point to a param, then we have to look into local declarations. 57 | let mut start_idx = self.param_count(); 58 | for locals_group in self.local_groups { 59 | let end_idx = start_idx 60 | .checked_add(locals_group.count()) 61 | .ok_or_else(|| Error(String::from("Locals range not in 32-bit range")))?; 62 | 63 | if idx >= start_idx && idx < end_idx { 64 | return Ok(locals_group.value_type()); 65 | } 66 | 67 | start_idx = end_idx; 68 | } 69 | 70 | // We didn't find anything, that's an error. 71 | // At this moment `start_idx` should hold the count of all locals 72 | // (since it's either set to the `end_idx` or equal to `params.len()`) 73 | let total_count = start_idx; 74 | 75 | Err(Error(format!( 76 | "Trying to access local with index {} when there are only {} locals", 77 | idx, total_count 78 | ))) 79 | } 80 | } 81 | 82 | #[cfg(test)] 83 | mod tests { 84 | use super::*; 85 | 86 | #[test] 87 | fn locals_it_works() { 88 | let params = vec![ValueType::I32, ValueType::I64]; 89 | let local_groups = vec![Local::new(2, ValueType::F32), Local::new(2, ValueType::F64)]; 90 | let locals = Locals::new(¶ms, &local_groups).unwrap(); 91 | 92 | assert_matches!(locals.type_of_local(0), Ok(ValueType::I32)); 93 | assert_matches!(locals.type_of_local(1), Ok(ValueType::I64)); 94 | assert_matches!(locals.type_of_local(2), Ok(ValueType::F32)); 95 | assert_matches!(locals.type_of_local(3), Ok(ValueType::F32)); 96 | assert_matches!(locals.type_of_local(4), Ok(ValueType::F64)); 97 | assert_matches!(locals.type_of_local(5), Ok(ValueType::F64)); 98 | assert_matches!(locals.type_of_local(6), Err(_)); 99 | } 100 | 101 | #[test] 102 | fn locals_no_declared_locals() { 103 | let params = vec![ValueType::I32]; 104 | let locals = Locals::new(¶ms, &[]).unwrap(); 105 | 106 | assert_matches!(locals.type_of_local(0), Ok(ValueType::I32)); 107 | assert_matches!(locals.type_of_local(1), Err(_)); 108 | } 109 | 110 | #[test] 111 | fn locals_no_params() { 112 | let local_groups = vec![Local::new(2, ValueType::I32), Local::new(3, ValueType::I64)]; 113 | let locals = Locals::new(&[], &local_groups).unwrap(); 114 | 115 | assert_matches!(locals.type_of_local(0), Ok(ValueType::I32)); 116 | assert_matches!(locals.type_of_local(1), Ok(ValueType::I32)); 117 | assert_matches!(locals.type_of_local(2), Ok(ValueType::I64)); 118 | assert_matches!(locals.type_of_local(3), Ok(ValueType::I64)); 119 | assert_matches!(locals.type_of_local(4), Ok(ValueType::I64)); 120 | assert_matches!(locals.type_of_local(5), Err(_)); 121 | } 122 | 123 | #[test] 124 | fn locals_u32_overflow() { 125 | let local_groups = vec![ 126 | Local::new(u32::max_value(), ValueType::I32), 127 | Local::new(1, ValueType::I64), 128 | ]; 129 | assert_matches!(Locals::new(&[], &local_groups), Err(_)); 130 | } 131 | } 132 | --------------------------------------------------------------------------------