From 91f64d40d4de5d6d3d459c202d44a2e790a756ac Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Thu, 6 May 2021 14:19:14 -0700 Subject: [PATCH] Implement the `allow-unknown-exports` option for the run command. This commit implements the `--allow-unknown-exports` option to the CLI run command that will ignore unknown exports in a command module rather than return an error. Fixes #2587. --- crates/wasmtime/src/linker.rs | 30 +++++++++++++++++++++++++++++- src/commands/run.rs | 6 ++++++ tests/all/linker.rs | 18 ++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/crates/wasmtime/src/linker.rs b/crates/wasmtime/src/linker.rs index cd2be6a32690..590ff155d33c 100644 --- a/crates/wasmtime/src/linker.rs +++ b/crates/wasmtime/src/linker.rs @@ -37,6 +37,7 @@ pub struct Linker { strings: Vec>, map: HashMap, allow_shadowing: bool, + allow_unknown_exports: bool, } #[derive(Hash, PartialEq, Eq)] @@ -69,6 +70,7 @@ impl Linker { string2idx: HashMap::new(), strings: Vec::new(), allow_shadowing: false, + allow_unknown_exports: false, } } @@ -102,6 +104,32 @@ impl Linker { self } + /// Configures whether this [`Linker`] will allow unknown exports from + /// command modules. + /// + /// By default a [`Linker`] will error when unknown exports are encountered + /// in a command module while using [`Linker::module`]. + /// + /// This method can be used to allow unknown exports from command modules. + /// + /// # Examples + /// + /// ``` + /// # use wasmtime::*; + /// # fn main() -> anyhow::Result<()> { + /// # let store = Store::default(); + /// # let module = Module::new(store.engine(), "(module)")?; + /// let mut linker = Linker::new(&store); + /// linker.allow_unknown_exports(true); + /// linker.module("mod", &module)?; + /// # Ok(()) + /// # } + /// ``` + pub fn allow_unknown_exports(&mut self, allow: bool) -> &mut Linker { + self.allow_unknown_exports = allow; + self + } + /// Defines a new item in this [`Linker`]. /// /// This method will add a new definition, by name, to this instance of @@ -469,7 +497,7 @@ impl Linker { // Allow an exported "__rtti_base" memory for compatibility with // AssemblyScript. warn!("command module exporting '__rtti_base' is deprecated; pass `--runtime half` to the AssemblyScript compiler"); - } else { + } else if !self.allow_unknown_exports { bail!("command export '{}' is not a function", export.name()); } } diff --git a/src/commands/run.rs b/src/commands/run.rs index 4d6bce5b0b5f..fb54466cba24 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -81,6 +81,10 @@ pub struct RunCommand { #[structopt(flatten)] common: CommonOptions, + /// Allow unknown exports when running commands. + #[structopt(long = "allow-unknown-exports")] + allow_unknown_exports: bool, + /// Grant access to the given host directory #[structopt(long = "dir", number_of_values = 1, value_name = "DIRECTORY")] dirs: Vec, @@ -146,6 +150,8 @@ impl RunCommand { let argv = self.compute_argv(); let mut linker = Linker::new(&store); + linker.allow_unknown_exports(self.allow_unknown_exports); + populate_with_wasi( &mut linker, preopen_dirs, diff --git a/tests/all/linker.rs b/tests/all/linker.rs index 2f1707dd7178..1b956633906d 100644 --- a/tests/all/linker.rs +++ b/tests/all/linker.rs @@ -162,6 +162,24 @@ fn module_interposition() -> Result<()> { Ok(()) } +#[test] +fn allow_unknown_exports() -> Result<()> { + let store = Store::default(); + let mut linker = Linker::new(&store); + let module = Module::new( + store.engine(), + r#"(module (func (export "_start")) (global (export "g") i32 (i32.const 0)))"#, + )?; + + assert!(linker.module("module", &module).is_err()); + + let mut linker = Linker::new(&store); + linker.allow_unknown_exports(true); + linker.module("module", &module)?; + + Ok(()) +} + #[test] fn no_leak() -> Result<()> { struct DropMe(Rc>);