Browse Source

Restore running precompiled modules with the CLI (#3343)

* Restore running precompiled modules with the CLI

This was accidentally broken when `Module::deserialize` was split out of
`Module::new` long ago, so this adds the detection in the CLI to call
the appropriate method to load the module. This feature is gated behind
an `--allow-precompiled` flag to enable, by default, passing arbitrary
user input to the `wasmtime` command.

Closes #3338

* Fix test on Windows
pull/3348/head
Alex Crichton 3 years ago
committed by GitHub
parent
commit
4d4779b563
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 41
      src/commands/run.rs
  2. 18
      tests/all/cli_tests.rs

41
src/commands/run.rs

@ -2,11 +2,13 @@
use crate::{CommonOptions, WasiModules};
use anyhow::{anyhow, bail, Context as _, Result};
use std::fs::File;
use std::io::Read;
use std::thread;
use std::time::Duration;
use std::{
ffi::{OsStr, OsString},
path::{Component, PathBuf},
path::{Component, Path, PathBuf},
process,
};
use structopt::{clap::AppSettings, StructOpt};
@ -80,6 +82,15 @@ pub struct RunCommand {
#[structopt(long = "allow-unknown-exports")]
allow_unknown_exports: bool,
/// Allow executing precompiled WebAssembly modules as `*.cwasm` files.
///
/// Note that this option is not safe to pass if the module being passed in
/// is arbitrary user input. Only `wasmtime`-precompiled modules generated
/// via the `wasmtime compile` command or equivalent should be passed as an
/// argument with this option specified.
#[structopt(long = "allow-precompiled")]
allow_precompiled: bool,
/// Grant access to the given host directory
#[structopt(long = "dir", number_of_values = 1, value_name = "DIRECTORY")]
dirs: Vec<String>,
@ -159,7 +170,7 @@ impl RunCommand {
// Load the preload wasm modules.
for (name, path) in self.preloads.iter() {
// Read the wasm module binary either as `*.wat` or a raw binary
let module = Module::from_file(&engine, path)?;
let module = self.load_module(&engine, path)?;
// Add the module's functions to the linker.
linker.module(&mut store, name, &module).context(format!(
@ -266,7 +277,7 @@ impl RunCommand {
// Read the wasm module binary either as `*.wat` or a raw binary.
// Use "" as a default module name.
let module = Module::from_file(linker.engine(), &self.module)?;
let module = self.load_module(linker.engine(), &self.module)?;
linker
.module(&mut *store, "", &module)
.context(format!("failed to instantiate {:?}", self.module))?;
@ -360,6 +371,30 @@ impl RunCommand {
Ok(())
}
fn load_module(&self, engine: &Engine, path: &Path) -> Result<Module> {
// Peek at the first few bytes of the file to figure out if this is
// something we can pass off to `deserialize_file` which is fastest if
// we don't actually read the whole file into memory. Note that this
// behavior is disabled by default, though, because it's not safe to
// pass arbitrary user input to this command with `--allow-precompiled`
let mut file =
File::open(path).with_context(|| format!("failed to open: {}", path.display()))?;
let mut magic = [0; 4];
if let Ok(()) = file.read_exact(&mut magic) {
if &magic == b"\x7fELF" {
if self.allow_precompiled {
return unsafe { Module::deserialize_file(engine, path) };
}
bail!(
"cannot load precompiled module `{}` unless --allow-precompiled is passed",
path.display()
)
}
}
Module::from_file(engine, path)
}
}
#[derive(Default)]

18
tests/all/cli_tests.rs

@ -2,7 +2,7 @@ use anyhow::{bail, Result};
use std::io::Write;
use std::path::Path;
use std::process::{Command, Output};
use tempfile::NamedTempFile;
use tempfile::{NamedTempFile, TempDir};
// Run the wasmtime CLI with the provided args and return the `Output`.
fn run_wasmtime_for_output(args: &[&str]) -> Result<Output> {
@ -381,3 +381,19 @@ fn exit_with_saved_fprs() -> Result<()> {
assert!(output.stdout.is_empty());
Ok(())
}
#[test]
fn run_cwasm() -> Result<()> {
let td = TempDir::new()?;
let cwasm = td.path().join("foo.cwasm");
let stdout = run_wasmtime(&[
"compile",
"tests/all/cli_tests/simple.wat",
"-o",
cwasm.to_str().unwrap(),
])?;
assert_eq!(stdout, "");
let stdout = run_wasmtime(&["run", "--allow-precompiled", cwasm.to_str().unwrap()])?;
assert_eq!(stdout, "");
Ok(())
}

Loading…
Cancel
Save