diff --git a/ci/run-wasi-crypto-example.sh b/ci/run-wasi-crypto-example.sh index 30bbada3c76a..b027e4834002 100755 --- a/ci/run-wasi-crypto-example.sh +++ b/ci/run-wasi-crypto-example.sh @@ -7,4 +7,4 @@ pushd "$RUST_BINDINGS" cargo build --release --target=wasm32-wasi popd -cargo run --features wasi-crypto -- run --wasi-modules=experimental-wasi-crypto "$RUST_BINDINGS/target/wasm32-wasi/release/wasi-crypto-guest.wasm" +cargo run --features wasi-crypto -- run "$RUST_BINDINGS/target/wasm32-wasi/release/wasi-crypto-guest.wasm" --wasi-modules=experimental-wasi-crypto diff --git a/ci/run-wasi-nn-example.sh b/ci/run-wasi-nn-example.sh index b8012120d3fa..82990d0bbda3 100755 --- a/ci/run-wasi-nn-example.sh +++ b/ci/run-wasi-nn-example.sh @@ -33,7 +33,7 @@ cp target/wasm32-wasi/release/wasi-nn-example.wasm $TMP_DIR popd # Run the example in Wasmtime (note that the example uses `fixture` as the expected location of the model/tensor files). -cargo run -- run --mapdir fixture::$TMP_DIR --wasi-modules=experimental-wasi-nn $TMP_DIR/wasi-nn-example.wasm +cargo run -- run --mapdir fixture::$TMP_DIR $TMP_DIR/wasi-nn-example.wasm --wasi-modules=experimental-wasi-nn # Clean up the temporary directory only if it was not specified (users may want to keep the directory around). if [[ $REMOVE_TMP_DIR -eq 1 ]]; then diff --git a/src/bin/wasmtime.rs b/src/bin/wasmtime.rs index d32a0b63f373..6d425625dfa4 100644 --- a/src/bin/wasmtime.rs +++ b/src/bin/wasmtime.rs @@ -4,7 +4,7 @@ //! See `wasmtime --help` for usage. use anyhow::Result; -use clap::Parser; +use clap::{error::ErrorKind, Parser}; use wasmtime_cli::commands::{ CompileCommand, ConfigCommand, ExploreCommand, RunCommand, SettingsCommand, WastCommand, }; @@ -27,24 +27,10 @@ use wasmtime_cli::commands::{ \n\ Invoking a specific function (e.g. `add`) in a WebAssembly module:\n\ \n \ - wasmtime example.wasm --invoke add 1 2\n", - - // This option enables the pattern below where we ask clap to parse twice - // sorta: once where it's trying to find a subcommand and once assuming - // a subcommand doesn't get passed. Clap should then, apparently, - // fill in the `subcommand` if found and otherwise fill in the - // `RunCommand`. - args_conflicts_with_subcommands = true + wasmtime example.wasm --invoke add 1 2\n" )] -struct Wasmtime { - #[clap(subcommand)] - subcommand: Option, - #[clap(flatten)] - run: RunCommand, -} - -#[derive(Parser)] -enum Subcommand { +enum Wasmtime { + // !!! IMPORTANT: if subcommands are added or removed, update `parse_module` in `src/commands/run.rs`. !!! /// Controls Wasmtime configuration settings Config(ConfigCommand), /// Compiles a WebAssembly module. @@ -62,20 +48,26 @@ enum Subcommand { impl Wasmtime { /// Executes the command. pub fn execute(self) -> Result<()> { - let subcommand = self.subcommand.unwrap_or(Subcommand::Run(self.run)); - match subcommand { - Subcommand::Config(c) => c.execute(), - Subcommand::Compile(c) => c.execute(), - Subcommand::Explore(c) => c.execute(), - Subcommand::Run(c) => c.execute(), - Subcommand::Settings(c) => c.execute(), - Subcommand::Wast(c) => c.execute(), + match self { + Self::Config(c) => c.execute(), + Self::Compile(c) => c.execute(), + Self::Explore(c) => c.execute(), + Self::Run(c) => c.execute(), + Self::Settings(c) => c.execute(), + Self::Wast(c) => c.execute(), } } } fn main() -> Result<()> { - Wasmtime::parse().execute() + Wasmtime::try_parse() + .unwrap_or_else(|e| match e.kind() { + ErrorKind::InvalidSubcommand | ErrorKind::UnknownArgument => { + Wasmtime::Run(RunCommand::parse()) + } + _ => e.exit(), + }) + .execute() } #[test] diff --git a/src/commands/run.rs b/src/commands/run.rs index 00ef5e1fead5..55b09b53616c 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -1,11 +1,14 @@ //! The module that implements the `wasmtime run` command. use anyhow::{anyhow, bail, Context as _, Result}; +use clap::builder::{OsStringValueParser, TypedValueParser}; use clap::Parser; use once_cell::sync::Lazy; +use std::ffi::OsStr; +use std::ffi::OsString; use std::fs::File; use std::io::Write; -use std::path::{Path, PathBuf}; +use std::path::{Component, Path, PathBuf}; use std::thread; use std::time::Duration; use wasmtime::{ @@ -36,6 +39,18 @@ use wasmtime_wasi_threads::WasiThreadsCtx; #[cfg(feature = "wasi-http")] use wasmtime_wasi_http::WasiHttp; +fn parse_module(s: OsString) -> anyhow::Result { + // Do not accept wasmtime subcommand names as the module name + match s.to_str() { + Some("help") | Some("config") | Some("run") | Some("wast") | Some("compile") => { + bail!("module name cannot be the same as a subcommand") + } + #[cfg(unix)] + Some("-") => Ok(PathBuf::from("/dev/stdin")), + _ => Ok(s.into()), + } +} + fn parse_env_var(s: &str) -> Result<(String, Option)> { let mut parts = s.splitn(2, '='); Ok(( @@ -96,7 +111,7 @@ static AFTER_HELP: Lazy = Lazy::new(|| crate::FLAG_EXPLANATIONS.to_strin /// Runs a WebAssembly module #[derive(Parser)] -#[structopt(name = "run", after_help = AFTER_HELP.as_str())] +#[structopt(name = "run", trailing_var_arg = true, after_help = AFTER_HELP.as_str())] pub struct RunCommand { #[clap(flatten)] common: CommonOptions, @@ -159,6 +174,14 @@ pub struct RunCommand { #[clap(long = "mapdir", number_of_values = 1, value_name = "GUEST_DIR::HOST_DIR", value_parser = parse_map_dirs)] map_dirs: Vec<(String, String)>, + /// The path of the WebAssembly module to run + #[clap( + required = true, + value_name = "MODULE", + value_parser = OsStringValueParser::new().try_map(parse_module), + )] + module: PathBuf, + /// Load the given WebAssembly module before the main module #[clap( long = "preload", @@ -202,6 +225,11 @@ pub struct RunCommand { #[clap(long = "coredump-on-trap", value_name = "PATH")] coredump_on_trap: Option, + // NOTE: this must come last for trailing varargs + /// The arguments to pass to the module + #[clap(value_name = "ARGS")] + module_args: Vec, + /// Maximum size, in bytes, that a linear memory is allowed to reach. /// /// Growth beyond this limit will cause `memory.grow` instructions in @@ -233,14 +261,6 @@ pub struct RunCommand { /// memory, for example. #[clap(long)] trap_on_grow_failure: bool, - - /// The WebAssembly module to run and arguments to pass to it. - /// - /// Arguments passed to the wasm module will be configured as WASI CLI - /// arguments unless the `--invoke` CLI argument is passed in which case - /// arguments will be interpreted as arguments to the function specified. - #[clap(value_name = "WASM", trailing_var_arg = true, required = true)] - module_and_args: Vec, } #[derive(Clone)] @@ -283,13 +303,13 @@ impl RunCommand { // Make wasi available by default. let preopen_dirs = self.compute_preopen_dirs()?; - let argv = self.compute_argv()?; + let argv = self.compute_argv(); let mut linker = Linker::new(&engine); linker.allow_unknown_exports(self.allow_unknown_exports); // Read the wasm module binary either as `*.wat` or a raw binary. - let module = self.load_module(linker.engine(), &self.module_and_args[0])?; + let module = self.load_module(linker.engine(), &self.module)?; let mut modules = vec![(String::new(), module.clone())]; let host = Host::default(); @@ -350,12 +370,8 @@ impl RunCommand { // Load the main wasm module. match self .load_main_module(&mut store, &mut linker, module, modules, &argv[0]) - .with_context(|| { - format!( - "failed to run main module `{}`", - self.module_and_args[0].display() - ) - }) { + .with_context(|| format!("failed to run main module `{}`", self.module.display())) + { Ok(()) => (), Err(e) => { // Exit the process if Wasmtime understands the error; @@ -404,25 +420,27 @@ impl RunCommand { Ok(listeners) } - fn compute_argv(&self) -> Result> { + fn compute_argv(&self) -> Vec { let mut result = Vec::new(); - for (i, arg) in self.module_and_args.iter().enumerate() { - // For argv[0], which is the program name. Only include the base - // name of the main wasm module, to avoid leaking path information. - let arg = if i == 0 { - arg.components().next_back().unwrap().as_os_str() - } else { - arg.as_ref() - }; - result.push( - arg.to_str() - .ok_or_else(|| anyhow!("failed to convert {arg:?} to utf-8"))? - .to_string(), - ); + // Add argv[0], which is the program name. Only include the base name of the + // main wasm module, to avoid leaking path information. + result.push( + self.module + .components() + .next_back() + .map(Component::as_os_str) + .and_then(OsStr::to_str) + .unwrap_or("") + .to_owned(), + ); + + // Add the remaining arguments. + for arg in self.module_args.iter() { + result.push(arg.clone()); } - Ok(result) + result } fn setup_epoch_handler( @@ -523,10 +541,9 @@ impl RunCommand { } // Use "" as a default module name. - linker.module(&mut *store, "", &module).context(format!( - "failed to instantiate {:?}", - self.module_and_args[0] - ))?; + linker + .module(&mut *store, "", &module) + .context(format!("failed to instantiate {:?}", self.module))?; // If a function to invoke was given, invoke it. let func = if let Some(name) = &self.invoke { @@ -567,7 +584,7 @@ impl RunCommand { is experimental and may break in the future" ); } - let mut args = self.module_and_args.iter().skip(1); + let mut args = self.module_args.iter(); let mut values = Vec::new(); for ty in ty.params() { let val = match args.next() { @@ -580,9 +597,6 @@ impl RunCommand { } } }; - let val = val - .to_str() - .ok_or_else(|| anyhow!("argument is not valid utf-8: {val:?}"))?; values.push(match ty { // TODO: integer parsing here should handle hexadecimal notation // like `0x0...`, but the Rust standard library currently only @@ -609,9 +623,7 @@ impl RunCommand { if let Err(err) = invoke_res { let err = if err.is::() { if let Some(coredump_path) = self.coredump_on_trap.as_ref() { - let source_name = self.module_and_args[0] - .to_str() - .unwrap_or_else(|| "unknown"); + let source_name = self.module.to_str().unwrap_or_else(|| "unknown"); if let Err(coredump_err) = generate_coredump(&err, &source_name, coredump_path) { @@ -652,12 +664,6 @@ impl RunCommand { } fn load_module(&self, engine: &Engine, path: &Path) -> Result { - let path = match path.to_str() { - #[cfg(unix)] - Some("-") => "/dev/stdin".as_ref(), - _ => path, - }; - if self.allow_precompiled { unsafe { Module::from_trusted_file(engine, path) } } else { diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs index d7fd98cc103f..b66263128360 100644 --- a/tests/all/cli_tests.rs +++ b/tests/all/cli_tests.rs @@ -1,21 +1,41 @@ #![cfg(not(miri))] -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use std::fs::File; -use std::io::Write; +use std::io::{Read, Write}; use std::path::Path; -use std::process::{Command, Output}; +use std::process::{Command, Output, Stdio}; use tempfile::{NamedTempFile, TempDir}; // Run the wasmtime CLI with the provided args and return the `Output`. // If the `stdin` is `Some`, opens the file and redirects to the child's stdin. pub fn run_wasmtime_for_output(args: &[&str], stdin: Option<&Path>) -> Result { let mut cmd = get_wasmtime_command()?; - cmd.args(args); - if let Some(file) = stdin { - cmd.stdin(File::open(file)?); + let stdin = stdin + .map(File::open) + .transpose() + .context("Cannot open a file to use as stdin")?; + + if let Some(mut f) = stdin { + let mut buf = Vec::new(); + f.read_to_end(&mut buf)?; + + let mut child = cmd + .stdout(Stdio::piped()) + .stdin(Stdio::piped()) + .args(args) + .spawn()?; + + let mut stdin = child.stdin.take().unwrap(); + std::thread::spawn(move || { + stdin + .write_all(&buf) + .expect("failed to write module to child stdin") + }); + child.wait_with_output().map_err(Into::into) + } else { + cmd.args(args).output().map_err(Into::into) } - cmd.output().map_err(Into::into) } /// Get the Wasmtime CLI as a [Command]. @@ -74,10 +94,10 @@ fn run_wasmtime_simple() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/simple.wat")?; run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--invoke", "simple", "--disable-cache", - wasm.path().to_str().unwrap(), "4", ])?; Ok(()) @@ -90,10 +110,10 @@ fn run_wasmtime_simple_fail_no_args() -> Result<()> { assert!( run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--disable-cache", "--invoke", "simple", - wasm.path().to_str().unwrap(), ]) .is_err(), "shall fail" @@ -108,11 +128,11 @@ fn run_coredump_smoketest() -> Result<()> { let coredump_arg = format!("--coredump-on-trap={}", coredump_file.path().display()); let err = run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--invoke", "a", "--disable-cache", &coredump_arg, - wasm.path().to_str().unwrap(), ]) .unwrap_err(); assert!(err.to_string().contains(&format!( @@ -128,29 +148,29 @@ fn run_wasmtime_simple_wat() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/simple.wat")?; run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--invoke", "simple", "--disable-cache", - wasm.path().to_str().unwrap(), "4", ])?; assert_eq!( run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--invoke", "get_f32", "--disable-cache", - wasm.path().to_str().unwrap(), ])?, "100\n" ); assert_eq!( run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--invoke", "get_f64", "--disable-cache", - wasm.path().to_str().unwrap(), ])?, "100\n" ); @@ -185,7 +205,7 @@ fn run_wasmtime_unreachable_wat() -> Result<()> { #[test] fn hello_wasi_snapshot0() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/hello_wasi_snapshot0.wat")?; - let stdout = run_wasmtime(&["--disable-cache", wasm.path().to_str().unwrap()])?; + let stdout = run_wasmtime(&[wasm.path().to_str().unwrap(), "--disable-cache"])?; assert_eq!(stdout, "Hello, world!\n"); Ok(()) } @@ -194,7 +214,7 @@ fn hello_wasi_snapshot0() -> Result<()> { #[test] fn hello_wasi_snapshot1() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/hello_wasi_snapshot1.wat")?; - let stdout = run_wasmtime(&["--disable-cache", wasm.path().to_str().unwrap()])?; + let stdout = run_wasmtime(&[wasm.path().to_str().unwrap(), "--disable-cache"])?; assert_eq!(stdout, "Hello, world!\n"); Ok(()) } @@ -205,10 +225,10 @@ fn timeout_in_start() -> Result<()> { let output = run_wasmtime_for_output( &[ "run", + wasm.path().to_str().unwrap(), "--wasm-timeout", "1ms", "--disable-cache", - wasm.path().to_str().unwrap(), ], None, )?; @@ -229,10 +249,10 @@ fn timeout_in_invoke() -> Result<()> { let output = run_wasmtime_for_output( &[ "run", + wasm.path().to_str().unwrap(), "--wasm-timeout", "1ms", "--disable-cache", - wasm.path().to_str().unwrap(), ], None, )?; @@ -252,7 +272,7 @@ fn timeout_in_invoke() -> Result<()> { fn exit2_wasi_snapshot0() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/exit2_wasi_snapshot0.wat")?; let output = - run_wasmtime_for_output(&["--disable-cache", wasm.path().to_str().unwrap()], None)?; + run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"], None)?; assert_eq!(output.status.code().unwrap(), 2); Ok(()) } @@ -262,7 +282,7 @@ fn exit2_wasi_snapshot0() -> Result<()> { fn exit2_wasi_snapshot1() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/exit2_wasi_snapshot1.wat")?; let output = - run_wasmtime_for_output(&["--disable-cache", wasm.path().to_str().unwrap()], None)?; + run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"], None)?; assert_eq!(output.status.code().unwrap(), 2); Ok(()) } @@ -272,7 +292,7 @@ fn exit2_wasi_snapshot1() -> Result<()> { fn exit125_wasi_snapshot0() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/exit125_wasi_snapshot0.wat")?; let output = - run_wasmtime_for_output(&["--disable-cache", wasm.path().to_str().unwrap()], None)?; + run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"], None)?; if cfg!(windows) { assert_eq!(output.status.code().unwrap(), 1); } else { @@ -286,7 +306,7 @@ fn exit125_wasi_snapshot0() -> Result<()> { fn exit125_wasi_snapshot1() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/exit125_wasi_snapshot1.wat")?; let output = - run_wasmtime_for_output(&["--disable-cache", wasm.path().to_str().unwrap()], None)?; + run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"], None)?; if cfg!(windows) { assert_eq!(output.status.code().unwrap(), 1); } else { @@ -300,7 +320,7 @@ fn exit125_wasi_snapshot1() -> Result<()> { fn exit126_wasi_snapshot0() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/exit126_wasi_snapshot0.wat")?; let output = - run_wasmtime_for_output(&["--disable-cache", wasm.path().to_str().unwrap()], None)?; + run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"], None)?; assert_eq!(output.status.code().unwrap(), 1); assert!(output.stdout.is_empty()); assert!(String::from_utf8_lossy(&output.stderr).contains("invalid exit status")); @@ -323,7 +343,7 @@ fn exit126_wasi_snapshot1() -> Result<()> { #[test] fn minimal_command() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/minimal-command.wat")?; - let stdout = run_wasmtime(&["--disable-cache", wasm.path().to_str().unwrap()])?; + let stdout = run_wasmtime(&[wasm.path().to_str().unwrap(), "--disable-cache"])?; assert_eq!(stdout, ""); Ok(()) } @@ -332,7 +352,7 @@ fn minimal_command() -> Result<()> { #[test] fn minimal_reactor() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/minimal-reactor.wat")?; - let stdout = run_wasmtime(&["--disable-cache", wasm.path().to_str().unwrap()])?; + let stdout = run_wasmtime(&[wasm.path().to_str().unwrap(), "--disable-cache"])?; assert_eq!(stdout, ""); Ok(()) } @@ -343,10 +363,10 @@ fn command_invoke() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/minimal-command.wat")?; run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--invoke", "_start", "--disable-cache", - wasm.path().to_str().unwrap(), ])?; Ok(()) } @@ -357,10 +377,10 @@ fn reactor_invoke() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/minimal-reactor.wat")?; run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--invoke", "_initialize", "--disable-cache", - wasm.path().to_str().unwrap(), ])?; Ok(()) } @@ -371,10 +391,10 @@ fn greeter() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/greeter_command.wat")?; let stdout = run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--disable-cache", "--preload", "reactor=tests/all/cli_tests/greeter_reactor.wat", - wasm.path().to_str().unwrap(), ])?; assert_eq!( stdout, @@ -389,10 +409,10 @@ fn greeter_preload_command() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/greeter_reactor.wat")?; let stdout = run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--disable-cache", "--preload", "reactor=tests/all/cli_tests/hello_wasi_snapshot1.wat", - wasm.path().to_str().unwrap(), ])?; assert_eq!(stdout, "Hello _initialize\n"); Ok(()) @@ -404,10 +424,10 @@ fn greeter_preload_callable_command() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/greeter_command.wat")?; let stdout = run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--disable-cache", "--preload", "reactor=tests/all/cli_tests/greeter_callable_command.wat", - wasm.path().to_str().unwrap(), ])?; assert_eq!(stdout, "Hello _start\nHello callable greet\nHello done\n"); Ok(()) @@ -419,7 +439,7 @@ fn greeter_preload_callable_command() -> Result<()> { fn exit_with_saved_fprs() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/exit_with_saved_fprs.wat")?; let output = - run_wasmtime_for_output(&["--disable-cache", wasm.path().to_str().unwrap()], None)?; + run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"], None)?; assert_eq!(output.status.code().unwrap(), 0); assert!(output.stdout.is_empty()); Ok(()) @@ -449,7 +469,7 @@ fn hello_wasi_snapshot0_from_stdin() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/hello_wasi_snapshot0.wat")?; let stdout = { let path = wasm.path(); - let args: &[&str] = &["--disable-cache", "-"]; + let args: &[&str] = &["-", "--disable-cache"]; let output = run_wasmtime_for_output(args, Some(path))?; if !output.status.success() { bail!( @@ -511,8 +531,6 @@ fn specify_env() -> Result<()> { #[cfg(unix)] #[test] fn run_cwasm_from_stdin() -> Result<()> { - use std::process::Stdio; - let td = TempDir::new()?; let cwasm = td.path().join("foo.cwasm"); let stdout = run_wasmtime(&[ @@ -522,32 +540,11 @@ fn run_cwasm_from_stdin() -> Result<()> { cwasm.to_str().unwrap(), ])?; assert_eq!(stdout, ""); - - // If stdin is literally the file itself then that should work let args: &[&str] = &["run", "--allow-precompiled", "-"]; - let output = get_wasmtime_command()? - .args(args) - .stdin(File::open(&cwasm)?) - .output()?; - assert!(output.status.success(), "a file as stdin should work"); - - // If stdin is a pipe, however, that should fail - let input = std::fs::read(&cwasm)?; - let mut child = get_wasmtime_command()? - .args(args) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn()?; - let mut stdin = child.stdin.take().unwrap(); - let t = std::thread::spawn(move || { - let _ = stdin.write_all(&input); - }); - let output = child.wait_with_output()?; + let output = run_wasmtime_for_output(args, Some(&cwasm))?; if output.status.success() { bail!("wasmtime should fail loading precompiled modules from piped files, but suceeded"); } - t.join().unwrap(); Ok(()) } @@ -585,6 +582,7 @@ fn run_simple_with_wasi_threads() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/simple.wat")?; let stdout = run_wasmtime(&[ "run", + wasm.path().to_str().unwrap(), "--wasi-modules", "experimental-wasi-threads", "--wasm-features", @@ -592,101 +590,12 @@ fn run_simple_with_wasi_threads() -> Result<()> { "--disable-cache", "--invoke", "simple", - wasm.path().to_str().unwrap(), "4", ])?; assert_eq!(stdout, "4\n"); Ok(()) } -#[test] -fn wasm_flags() -> Result<()> { - // Any argument after the wasm module should be interpreted as for the - // command itself - let stdout = run_wasmtime(&[ - "run", - "tests/all/cli_tests/print-arguments.wat", - "--argument", - "-for", - "the", - "command", - ])?; - assert_eq!( - stdout, - "\ - print-arguments.wat\n\ - --argument\n\ - -for\n\ - the\n\ - command\n\ - " - ); - let stdout = run_wasmtime(&["run", "tests/all/cli_tests/print-arguments.wat", "-"])?; - assert_eq!( - stdout, - "\ - print-arguments.wat\n\ - -\n\ - " - ); - let stdout = run_wasmtime(&["run", "tests/all/cli_tests/print-arguments.wat", "--"])?; - assert_eq!( - stdout, - "\ - print-arguments.wat\n\ - --\n\ - " - ); - let stdout = run_wasmtime(&[ - "run", - "tests/all/cli_tests/print-arguments.wat", - "--", - "--", - "-a", - "b", - ])?; - assert_eq!( - stdout, - "\ - print-arguments.wat\n\ - --\n\ - --\n\ - -a\n\ - b\n\ - " - ); - Ok(()) -} - -#[test] -fn name_same_as_builtin_command() -> Result<()> { - // a bare subcommand shouldn't run successfully - let output = get_wasmtime_command()? - .current_dir("tests/all/cli_tests") - .arg("run") - .output()?; - assert!(!output.status.success()); - - // a `--` prefix should let everything else get interpreted as a wasm - // module and arguments, even if the module has a name like `run` - let output = get_wasmtime_command()? - .current_dir("tests/all/cli_tests") - .arg("--") - .arg("run") - .output()?; - assert!(output.status.success(), "expected success got {output:#?}"); - - // Passing options before the subcommand should work and doesn't require - // `--` to disambiguate - let output = get_wasmtime_command()? - .current_dir("tests/all/cli_tests") - .arg("--disable-cache") - .arg("run") - .output()?; - assert!(output.status.success(), "expected success got {output:#?}"); - Ok(()) -} - #[test] #[cfg(unix)] fn run_just_stdin_argument() -> Result<()> { @@ -698,26 +607,6 @@ fn run_just_stdin_argument() -> Result<()> { Ok(()) } -#[test] -fn wasm_flags_without_subcommand() -> Result<()> { - let output = get_wasmtime_command()? - .current_dir("tests/all/cli_tests/") - .arg("print-arguments.wat") - .arg("-foo") - .arg("bar") - .output()?; - assert!(output.status.success()); - assert_eq!( - String::from_utf8_lossy(&output.stdout), - "\ - print-arguments.wat\n\ - -foo\n\ - bar\n\ - " - ); - Ok(()) -} - #[test] fn wasi_misaligned_pointer() -> Result<()> { let output = get_wasmtime_command()? diff --git a/tests/all/cli_tests/print-arguments.wat b/tests/all/cli_tests/print-arguments.wat deleted file mode 100644 index 93e4558c46f0..000000000000 --- a/tests/all/cli_tests/print-arguments.wat +++ /dev/null @@ -1,75 +0,0 @@ -(module - (import "wasi_snapshot_preview1" "fd_write" - (func $fd_write (param i32 i32 i32 i32) (result i32))) - - (import "wasi_snapshot_preview1" "args_get" - (func $args_get (param i32 i32) (result i32))) - - (memory (export "memory") 1) - - (func (export "_start") - (local $argptrs i32) - (local $argmem i32) - (local $arg i32) - - (local.set $argptrs (i32.mul (memory.grow (i32.const 1)) (i32.const 65536))) - (local.set $argmem (i32.mul (memory.grow (i32.const 1)) (i32.const 65536))) - - (if (i32.ne - (call $args_get (local.get $argptrs) (local.get $argmem)) - (i32.const 0)) - (unreachable)) - - (loop - (local.set $arg (i32.load (local.get $argptrs))) - (local.set $argptrs (i32.add (local.get $argptrs) (i32.const 4))) - (if (i32.eq (local.get $arg) (i32.const 0)) (return)) - - (call $write_all (local.get $arg) (call $strlen (local.get $arg))) - (call $write_all (i32.const 10) (i32.const 1)) - br 0 - ) - ) - - (func $write_all (param $ptr i32) (param $len i32) - (local $rc i32) - (local $iov i32) - (local $written i32) - - (local.set $written (i32.const 80)) - (local.set $iov (i32.const 100)) - - (loop - (local.get $len) - if - (i32.store (local.get $iov) (local.get $ptr)) - (i32.store offset=4 (local.get $iov) (local.get $len)) - (local.set $rc - (call $fd_write - (i32.const 1) - (local.get $iov) - (i32.const 1) - (local.get $written))) - (if (i32.ne (local.get $rc) (i32.const 0)) (unreachable)) - - (local.set $len (i32.sub (local.get $len) (i32.load (local.get $written)))) - (local.set $ptr (i32.add (local.get $ptr) (i32.load (local.get $written)))) - end - ) - ) - - (func $strlen (param $ptr i32) (result i32) - (local $len i32) - (loop - (i32.load8_u (i32.add (local.get $ptr) (local.get $len))) - if - (local.set $len (i32.add (local.get $len) (i32.const 1))) - br 1 - end - ) - local.get $len - ) - - (data (i32.const 10) "\n") -) - diff --git a/tests/all/cli_tests/run b/tests/all/cli_tests/run deleted file mode 100644 index 4139404d3725..000000000000 --- a/tests/all/cli_tests/run +++ /dev/null @@ -1,3 +0,0 @@ -(module - (func (export "_start")) -) diff --git a/tests/all/debug/gdb.rs b/tests/all/debug/gdb.rs index 3ef3518b21ed..6f5bbdb338dd 100644 --- a/tests/all/debug/gdb.rs +++ b/tests/all/debug/gdb.rs @@ -59,9 +59,9 @@ pub fn test_debug_dwarf_gdb() -> Result<()> { &[ "--disable-cache", "-g", + "tests/all/debug/testsuite/fib-wasm.wasm", "--invoke", "fib", - "tests/all/debug/testsuite/fib-wasm.wasm", "3", ], r#"set breakpoint pending on diff --git a/tests/all/debug/lldb.rs b/tests/all/debug/lldb.rs index b6a097eb60e7..08fc344f880b 100644 --- a/tests/all/debug/lldb.rs +++ b/tests/all/debug/lldb.rs @@ -64,9 +64,9 @@ pub fn test_debug_dwarf_lldb() -> Result<()> { &[ "--disable-cache", "-g", + "tests/all/debug/testsuite/fib-wasm.wasm", "--invoke", "fib", - "tests/all/debug/testsuite/fib-wasm.wasm", "3", ], r#"b fib @@ -105,9 +105,9 @@ pub fn test_debug_dwarf5_lldb() -> Result<()> { &[ "--disable-cache", "-g", + "tests/all/debug/testsuite/fib-wasm-dwarf5.wasm", "--invoke", "fib", - "tests/all/debug/testsuite/fib-wasm-dwarf5.wasm", "3", ], r#"b fib diff --git a/tests/all/wasi_testsuite.rs b/tests/all/wasi_testsuite.rs index 8edeecaa8cbd..b1708a3fa017 100644 --- a/tests/all/wasi_testsuite.rs +++ b/tests/all/wasi_testsuite.rs @@ -118,6 +118,11 @@ fn build_command>(module: P, extra_flags: &[&str], spec: &Spec) - cmd.arg(format!("{}::{}", dir, parent_dir.join(dir).display())); } } + cmd.arg(module.as_ref().to_str().unwrap()); + if let Some(spec_args) = &spec.args { + cmd.args(spec_args); + } + // Add environment variables as CLI arguments. if let Some(env) = &spec.env { for env_pair in env { @@ -126,10 +131,6 @@ fn build_command>(module: P, extra_flags: &[&str], spec: &Spec) - } cmd.envs(env); } - cmd.arg(module.as_ref().to_str().unwrap()); - if let Some(spec_args) = &spec.args { - cmd.args(spec_args); - } Ok(cmd) }