Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add validate subcommand #323

Merged
merged 3 commits into from
Apr 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/runtime-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ edition = "2018"
[dependencies]
nix = "0.12.0"
page_size = "0.4.1"
wasmparser = "0.23.0"
wasmparser = "0.29.2"
parking_lot = "0.7.1"
lazy_static = "1.2.0"
indexmap = "1.0.2"
Expand Down
9 changes: 7 additions & 2 deletions lib/runtime-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,18 @@ pub fn compile_with_config(
/// WebAssembly specification. Returns `true` if validation
/// succeeded, `false` if validation failed.
pub fn validate(wasm: &[u8]) -> bool {
validate_and_report_errors(wasm).is_ok()
}

/// The same as `validate` but with an Error message on failure
pub fn validate_and_report_errors(wasm: &[u8]) -> ::std::result::Result<(), String> {
use wasmparser::WasmDecoder;
let mut parser = wasmparser::ValidatingParser::new(wasm, None);
loop {
let state = parser.read();
match *state {
wasmparser::ParserState::EndWasm => break true,
wasmparser::ParserState::Error(_) => break false,
wasmparser::ParserState::EndWasm => break Ok(()),
wasmparser::ParserState::Error(e) => break Err(format!("{}", e)),
_ => {}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/runtime-core/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl ModuleInfo {
let len = reader.bytes_remaining();
let bytes = reader.read_bytes(len)?;
let data = bytes.to_vec();
let name = String::from_utf8_lossy(name).to_string();
let name = name.to_string();
self.custom_sections.insert(name, data);
}
}
Expand Down
52 changes: 51 additions & 1 deletion src/bin/wasmer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use structopt::StructOpt;
use wasmer::webassembly::InstanceABI;
use wasmer::*;
use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH};
use wasmer_runtime_core::backend::CompilerConfig;
use wasmer_runtime_core::{self, backend::CompilerConfig};
#[cfg(feature = "wasi")]
use wasmer_wasi;

Expand All @@ -29,6 +29,10 @@ enum CLIOptions {
#[structopt(name = "cache")]
Cache(Cache),

/// Validate a Web Assembly binary
#[structopt(name = "validate")]
Validate(Validate),

/// Update wasmer to the latest version
#[structopt(name = "self-update")]
SelfUpdate,
Expand Down Expand Up @@ -64,6 +68,13 @@ enum Cache {
Dir,
}

#[derive(Debug, StructOpt)]
struct Validate {
/// Input file
#[structopt(parse(from_os_str))]
path: PathBuf,
}

/// Read the contents of a file
fn read_file_contents(path: &PathBuf) -> Result<Vec<u8>, io::Error> {
let mut buffer: Vec<u8> = Vec::new();
Expand Down Expand Up @@ -267,6 +278,42 @@ fn run(options: Run) {
}
}

fn validate_wasm(validate: Validate) -> Result<(), String> {
let wasm_path = validate.path;
let wasm_path_as_str = wasm_path.to_str().unwrap();

let wasm_binary: Vec<u8> = read_file_contents(&wasm_path).map_err(|err| {
format!(
"Can't read the file {}: {}",
wasm_path.as_os_str().to_string_lossy(),
err
)
})?;

if !utils::is_wasm_binary(&wasm_binary) {
return Err(format!(
"Cannot recognize \"{}\" as a WASM binary",
wasm_path_as_str,
));
}

wasmer_runtime_core::validate_and_report_errors(&wasm_binary)
.map_err(|err| format!("Validation failed: {}", err))?;

Ok(())
}

/// Runs logic for the `validate` subcommand
fn validate(validate: Validate) {
match validate_wasm(validate) {
Err(message) => {
eprintln!("Error: {}", message);
exit(-1);
}
_ => (),
}
}

fn main() {
let options = CLIOptions::from_args();
match options {
Expand All @@ -291,6 +338,9 @@ fn main() {
println!("{}", get_cache_dir().to_string_lossy());
}
},
CLIOptions::Validate(validate_options) => {
validate(validate_options);
}
#[cfg(target_os = "windows")]
CLIOptions::Cache(_) => {
println!("Caching is disabled for Windows.");
Expand Down