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
This commit is contained in:
@@ -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)]
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user