66) ]
77
88use anyhow:: { anyhow, bail, Context as _, Error , Result } ;
9- use clap:: builder:: { OsStringValueParser , TypedValueParser } ;
109use clap:: Parser ;
11- use std:: ffi:: OsStr ;
12- use std:: ffi:: OsString ;
1310use std:: fs:: File ;
1411use std:: io:: Write ;
1512use std:: path:: { Path , PathBuf } ;
@@ -38,18 +35,6 @@ use wasmtime_wasi_threads::WasiThreadsCtx;
3835#[ cfg( feature = "wasi-http" ) ]
3936use wasmtime_wasi_http:: WasiHttpCtx ;
4037
41- fn parse_module ( s : OsString ) -> anyhow:: Result < PathBuf > {
42- // Do not accept wasmtime subcommand names as the module name
43- match s. to_str ( ) {
44- Some ( "help" ) | Some ( "config" ) | Some ( "run" ) | Some ( "wast" ) | Some ( "compile" ) => {
45- bail ! ( "module name cannot be the same as a subcommand" )
46- }
47- #[ cfg( unix) ]
48- Some ( "-" ) => Ok ( PathBuf :: from ( "/dev/stdin" ) ) ,
49- _ => Ok ( s. into ( ) ) ,
50- }
51- }
52-
5338fn parse_env_var ( s : & str ) -> Result < ( String , Option < String > ) > {
5439 let mut parts = s. splitn ( 2 , '=' ) ;
5540 Ok ( (
@@ -100,7 +85,11 @@ fn parse_profile(s: &str) -> Result<Profile> {
10085
10186/// Runs a WebAssembly module
10287#[ derive( Parser ) ]
88+ <<<<<<< HEAD
10389#[ structopt ( name = "run" , trailing_var_arg = true ) ]
90+ =======
91+ #[ structopt ( name = "run" , after_help = AFTER_HELP . as_str ( ) ) ]
92+ >>>>>>> 562330 d0e2 ( Require Wasmtime options come before wasm modules)
10493pub struct RunCommand {
10594 #[ clap ( flatten ) ]
10695 common: CommonOptions ,
@@ -137,13 +126,30 @@ pub struct RunCommand {
137126 #[ clap( long, value_name = "FUNCTION" ) ]
138127 invoke: Option <String >,
139128
129+ <<<<<<< HEAD
140130 /// The path of the WebAssembly module to run
141131 #[ clap(
142132 required = true ,
143133 value_name = "MODULE" ,
144134 value_parser = OsStringValueParser :: new( ) . try_map( parse_module) ,
145135 ) ]
146136 module: PathBuf ,
137+ =======
138+ /// Grant access to a guest directory mapped as a host directory
139+ #[ clap( long = "mapdir" , number_of_values = 1 , value_name = "GUEST_DIR::HOST_DIR" , value_parser = parse_map_dirs) ]
140+ map_dirs: Vec <( String , String ) >,
141+
142+ /// Pre-load machine learning graphs (i.e., models) for use by wasi-nn.
143+ ///
144+ /// Each use of the flag will preload a ML model from the host directory
145+ /// using the given model encoding. The model will be mapped to the
146+ /// directory name: e.g., `--wasi-nn-graph openvino:/foo/bar` will preload
147+ /// an OpenVINO model named `bar`. Note that which model encodings are
148+ /// available is dependent on the backends implemented in the
149+ /// `wasmtime_wasi_nn` crate.
150+ #[ clap( long = "wasi-nn-graph" , value_name = "FORMAT::HOST_DIR" , value_parser = parse_graphs) ]
151+ graphs: Vec <( String , String ) >,
152+ >>>>>>> 562330 d0e2 ( Require Wasmtime options come before wasm modules)
147153
148154 /// Load the given WebAssembly module before the main module
149155 #[ clap(
@@ -176,10 +182,70 @@ pub struct RunCommand {
176182 ) ]
177183 profile: Option <Profile >,
178184
185+ <<<<<<< HEAD
179186 // NOTE: this must come last for trailing varargs
180187 /// The arguments to pass to the module
181188 #[ clap( value_name = "ARGS" ) ]
182189 module_args: Vec <String >,
190+ =======
191+ /// Enable coredump generation after a WebAssembly trap.
192+ #[ clap( long = "coredump-on-trap" , value_name = "PATH" ) ]
193+ coredump_on_trap: Option <String >,
194+
195+ /// Maximum size, in bytes, that a linear memory is allowed to reach.
196+ ///
197+ /// Growth beyond this limit will cause `memory.grow` instructions in
198+ /// WebAssembly modules to return -1 and fail.
199+ #[ clap( long, value_name = "BYTES" ) ]
200+ max_memory_size: Option <usize>,
201+
202+ /// Maximum size, in table elements, that a table is allowed to reach.
203+ #[ clap( long) ]
204+ max_table_elements: Option <u32>,
205+
206+ /// Maximum number of WebAssembly instances allowed to be created.
207+ #[ clap( long) ]
208+ max_instances: Option <usize>,
209+
210+ /// Maximum number of WebAssembly tables allowed to be created.
211+ #[ clap( long) ]
212+ max_tables: Option <usize>,
213+
214+ /// Maximum number of WebAssembly linear memories allowed to be created.
215+ #[ clap( long) ]
216+ max_memories: Option <usize>,
217+
218+ /// Force a trap to be raised on `memory.grow` and `table.grow` failure
219+ /// instead of returning -1 from these instructions.
220+ ///
221+ /// This is not necessarily a spec-compliant option to enable but can be
222+ /// useful for tracking down a backtrace of what is requesting so much
223+ /// memory, for example.
224+ #[ clap( long) ]
225+ trap_on_grow_failure: bool ,
226+
227+ /// Enables memory error checking.
228+ ///
229+ /// See wmemcheck.md for documentation on how to use.
230+ #[ clap( long) ]
231+ wmemcheck: bool ,
232+
233+ /// The WebAssembly module to run and arguments to pass to it.
234+ ///
235+ /// Arguments passed to the wasm module will be configured as WASI CLI
236+ /// arguments unless the `--invoke` CLI argument is passed in which case
237+ /// arguments will be interpreted as arguments to the function specified.
238+ #[ clap( value_name = "WASM" , trailing_var_arg = true , required = true ) ]
239+ module_and_args: Vec <PathBuf >,
240+
241+ /// Indicates that the implementation of WASI preview1 should be backed by
242+ /// the preview2 implementation for components.
243+ ///
244+ /// This will become the default in the future and this option will be
245+ /// removed. For now this is primarily here for testing.
246+ #[ clap( long) ]
247+ preview2: bool ,
248+ >>>>>>> 562330 d0e2 ( Require Wasmtime options come before wasm modules)
183249}
184250
185251#[ derive( Clone ) ]
@@ -242,7 +308,7 @@ impl RunCommand {
242308 let engine = Engine :: new ( & config) ?;
243309
244310 // Read the wasm module binary either as `*.wat` or a raw binary.
245- let main = self . load_module ( & engine, & self . module ) ?;
311+ let main = self . load_module ( & engine, & self . module_and_args [ 0 ] ) ?;
246312
247313 // Validate coredump-on-trap argument
248314 if let Some ( coredump_path) = & self . common . debug . coredump {
@@ -335,8 +401,12 @@ impl RunCommand {
335401 // Load the main wasm module.
336402 match self
337403 . load_main_module ( & mut store, & mut linker, & main, modules)
338- . with_context ( || format ! ( "failed to run main module `{}`" , self . module. display( ) ) )
339- {
404+ . with_context ( || {
405+ format ! (
406+ "failed to run main module `{}`" ,
407+ self . module_and_args[ 0 ] . display( )
408+ )
409+ } ) {
340410 Ok ( ( ) ) => ( ) ,
341411 Err ( e) => {
342412 // Exit the process if Wasmtime understands the error;
@@ -377,27 +447,25 @@ impl RunCommand {
377447 Ok ( listeners)
378448 }
379449
380- fn compute_argv ( & self ) -> Vec < String > {
450+ fn compute_argv ( & self ) -> Result < Vec < String > > {
381451 let mut result = Vec :: new ( ) ;
382452
383- // Add argv[0], which is the program name. Only include the base name of the
384- // main wasm module, to avoid leaking path information.
385- result. push (
386- self . module
387- . components ( )
388- . next_back ( )
389- . map ( |c| c. as_os_str ( ) )
390- . and_then ( OsStr :: to_str)
391- . unwrap_or ( "" )
392- . to_owned ( ) ,
393- ) ;
394-
395- // Add the remaining arguments.
396- for arg in self . module_args . iter ( ) {
397- result. push ( arg. clone ( ) ) ;
453+ for ( i, arg) in self . module_and_args . iter ( ) . enumerate ( ) {
454+ // For argv[0], which is the program name. Only include the base
455+ // name of the main wasm module, to avoid leaking path information.
456+ let arg = if i == 0 {
457+ arg. components ( ) . next_back ( ) . unwrap ( ) . as_os_str ( )
458+ } else {
459+ arg. as_ref ( )
460+ } ;
461+ result. push (
462+ arg. to_str ( )
463+ . ok_or_else ( || anyhow ! ( "failed to convert {arg:?} to utf-8" ) ) ?
464+ . to_string ( ) ,
465+ ) ;
398466 }
399467
400- result
468+ Ok ( result)
401469 }
402470
403471 fn setup_epoch_handler (
@@ -406,7 +474,7 @@ impl RunCommand {
406474 modules : Vec < ( String , Module ) > ,
407475 ) -> Box < dyn FnOnce ( & mut Store < Host > ) > {
408476 if let Some ( Profile :: Guest { path, interval } ) = & self . profile {
409- let module_name = self . module . to_str ( ) . unwrap_or ( "<main module>" ) ;
477+ let module_name = self . module_and_args [ 0 ] . to_str ( ) . unwrap_or ( "<main module>" ) ;
410478 let interval = * interval;
411479 store. data_mut ( ) . guest_profiler =
412480 Some ( Arc :: new ( GuestProfiler :: new ( module_name, interval, modules) ) ) ;
@@ -512,9 +580,10 @@ impl RunCommand {
512580 CliLinker :: Core ( linker) => {
513581 // Use "" as a default module name.
514582 let module = module. unwrap_core ( ) ;
515- linker
516- . module ( & mut * store, "" , & module)
517- . context ( format ! ( "failed to instantiate {:?}" , self . module) ) ?;
583+ linker. module ( & mut * store, "" , & module) . context ( format ! (
584+ "failed to instantiate {:?}" ,
585+ self . module_and_args[ 0 ]
586+ ) ) ?;
518587
519588 // If a function to invoke was given, invoke it.
520589 let func = if let Some ( name) = & self . invoke {
@@ -569,7 +638,7 @@ impl RunCommand {
569638 is experimental and may break in the future"
570639 ) ;
571640 }
572- let mut args = self . module_args . iter ( ) ;
641+ let mut args = self . module_and_args . iter ( ) . skip ( 1 ) ;
573642 let mut values = Vec :: new ( ) ;
574643 for ty in ty. params ( ) {
575644 let val = match args. next ( ) {
@@ -582,6 +651,9 @@ impl RunCommand {
582651 }
583652 }
584653 } ;
654+ let val = val
655+ . to_str ( )
656+ . ok_or_else ( || anyhow ! ( "argument is not valid utf-8: {val:?}" ) ) ?;
585657 values. push ( match ty {
586658 // TODO: integer parsing here should handle hexadecimal notation
587659 // like `0x0...`, but the Rust standard library currently only
@@ -639,7 +711,9 @@ impl RunCommand {
639711 if !err. is :: < wasmtime:: Trap > ( ) {
640712 return err;
641713 }
642- let source_name = self . module . to_str ( ) . unwrap_or_else ( || "unknown" ) ;
714+ let source_name = self . module_and_args [ 0 ]
715+ . to_str ( )
716+ . unwrap_or_else ( || "unknown" ) ;
643717
644718 if let Err ( coredump_err) = generate_coredump ( & err, & source_name, coredump_path) {
645719 eprintln ! ( "warning: coredump failed to generate: {}" , coredump_err) ;
@@ -884,7 +958,7 @@ impl RunCommand {
884958
885959 fn set_preview1_ctx ( & self , store : & mut Store < Host > ) -> Result < ( ) > {
886960 let mut builder = WasiCtxBuilder :: new ( ) ;
887- builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ) ?;
961+ builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ? ) ?;
888962
889963 for ( key, value) in self . vars . iter ( ) {
890964 let value = match value {
@@ -916,7 +990,7 @@ impl RunCommand {
916990
917991 fn set_preview2_ctx ( & self , store : & mut Store < Host > ) -> Result < ( ) > {
918992 let mut builder = preview2:: WasiCtxBuilder :: new ( ) ;
919- builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ) ;
993+ builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ? ) ;
920994
921995 for ( key, value) in self . vars . iter ( ) {
922996 let value = match value {
0 commit comments