diff --git a/host/src/main.rs b/host/src/main.rs index cf11313c..35aa68b3 100644 --- a/host/src/main.rs +++ b/host/src/main.rs @@ -29,7 +29,11 @@ async fn main() -> Result<()> { let (wasi, _instance) = Wasi::instantiate_async(&mut store, &component, &linker).await?; - wasi.command(&mut store, 0, 0, &[], &[], &[]).await?; + let result: Result<(), ()> = wasi.command(&mut store, 0, 0, &[], &[], &[]).await?; + + if result.is_err() { + anyhow::bail!("command returned with failing exit status"); + } Ok(()) } diff --git a/host/tests/runtime.rs b/host/tests/runtime.rs index 8137df64..201a4fbd 100644 --- a/host/tests/runtime.rs +++ b/host/tests/runtime.rs @@ -46,8 +46,8 @@ async fn run_hello_stdout(mut store: Store, wasi: Wasi) -> Result<()> { &[], &[], ) - .await?; - Ok(()) + .await? + .map_err(|()| anyhow::anyhow!("command returned with failing exit status")) } async fn run_panic(mut store: Store, wasi: Wasi) -> Result<()> { @@ -84,8 +84,8 @@ async fn run_args(mut store: Store, wasi: Wasi) -> Result<()> { &[], &[], ) - .await?; - Ok(()) + .await? + .map_err(|()| anyhow::anyhow!("command returned with failing exit status")) } async fn run_random(mut store: Store, wasi: Wasi) -> Result<()> { @@ -119,8 +119,8 @@ async fn run_random(mut store: Store, wasi: Wasi) -> Result<()> { &[], &[], ) - .await?; - Ok(()) + .await? + .map_err(|()| anyhow::anyhow!("command returned with failing exit status")) } async fn run_time(mut store: Store, wasi: Wasi) -> Result<()> { @@ -176,8 +176,8 @@ async fn run_time(mut store: Store, wasi: Wasi) -> Result<()> { &[], &[], ) - .await?; - Ok(()) + .await? + .map_err(|()| anyhow::anyhow!("command returned with failing exit status")) } async fn run_stdin(mut store: Store, wasi: Wasi) -> Result<()> { @@ -195,8 +195,8 @@ async fn run_stdin(mut store: Store, wasi: Wasi) -> Result<()> { &[], &[], ) - .await?; - Ok(()) + .await? + .map_err(|()| anyhow::anyhow!("command returned with failing exit status")) } async fn run_env(mut store: Store, wasi: Wasi) -> Result<()> { @@ -208,8 +208,8 @@ async fn run_env(mut store: Store, wasi: Wasi) -> Result<()> { &[("frabjous", "day"), ("callooh", "callay")], &[], ) - .await?; - Ok(()) + .await? + .map_err(|()| anyhow::anyhow!("command returned with failing exit status")) } async fn run_file_read(mut store: Store, wasi: Wasi) -> Result<()> { @@ -232,6 +232,72 @@ async fn run_file_read(mut store: Store, wasi: Wasi) -> Result<()> { &[], &[(descriptor, "/")], ) - .await?; + .await? + .map_err(|()| anyhow::anyhow!("command returned with failing exit status")) +} + +async fn run_exit_success(mut store: Store, wasi: Wasi) -> Result<()> { + let r = wasi + .command( + &mut store, + 0 as host::Descriptor, + 1 as host::Descriptor, + &[], + &[("frabjous", "day"), ("callooh", "callay")], + &[], + ) + .await; + let err = r.unwrap_err(); + let status = err.downcast_ref::().unwrap(); + assert_eq!(status.0, 0); + Ok(()) +} + +async fn run_exit_default(mut store: Store, wasi: Wasi) -> Result<()> { + let r = wasi + .command( + &mut store, + 0 as host::Descriptor, + 1 as host::Descriptor, + &[], + &[("frabjous", "day"), ("callooh", "callay")], + &[], + ) + .await?; + assert!(r.is_ok()); + Ok(()) +} + +async fn run_exit_failure(mut store: Store, wasi: Wasi) -> Result<()> { + let r = wasi + .command( + &mut store, + 0 as host::Descriptor, + 1 as host::Descriptor, + &[], + &[("frabjous", "day"), ("callooh", "callay")], + &[], + ) + .await; + let err = r.unwrap_err(); + let status = err.downcast_ref::().unwrap(); + assert_eq!(status.0, 1); + Ok(()) +} + +async fn run_exit_panic(mut store: Store, wasi: Wasi) -> Result<()> { + let r = wasi + .command( + &mut store, + 0 as host::Descriptor, + 1 as host::Descriptor, + &[], + &[("frabjous", "day"), ("callooh", "callay")], + &[], + ) + .await; + let err = r.unwrap_err(); + // The panic should trap. + assert!(err.downcast_ref::().is_none()); Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index f8d99b45..5ad723e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ pub unsafe extern "C" fn command( args_len: usize, env_vars: StrTupleList, preopens: PreopenList, -) { +) -> Result<(), ()> { // TODO: ideally turning off `command` would remove this import and the // `*.wit` metadata entirely but doing that ergonomically will likely // require some form of `use` to avoid duplicating lots of `*.wit` bits. @@ -86,6 +86,7 @@ pub unsafe extern "C" fn command( fn _start(); } _start(); + Ok(()) } // We're avoiding static initializers, so replace the standard assert macros diff --git a/test-programs/src/bin/exit_default.rs b/test-programs/src/bin/exit_default.rs new file mode 100644 index 00000000..f328e4d9 --- /dev/null +++ b/test-programs/src/bin/exit_default.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/test-programs/src/bin/exit_failure.rs b/test-programs/src/bin/exit_failure.rs new file mode 100644 index 00000000..bd7408ef --- /dev/null +++ b/test-programs/src/bin/exit_failure.rs @@ -0,0 +1,3 @@ +fn main() { + std::process::exit(1) +} diff --git a/test-programs/src/bin/exit_panic.rs b/test-programs/src/bin/exit_panic.rs new file mode 100644 index 00000000..d44527c6 --- /dev/null +++ b/test-programs/src/bin/exit_panic.rs @@ -0,0 +1,3 @@ +fn main() { + panic!("Curiouser and curiouser!") +} diff --git a/test-programs/src/bin/exit_success.rs b/test-programs/src/bin/exit_success.rs new file mode 100644 index 00000000..d93f0045 --- /dev/null +++ b/test-programs/src/bin/exit_success.rs @@ -0,0 +1,3 @@ +fn main() { + std::process::exit(0) +} diff --git a/wit/wasi.wit b/wit/wasi.wit index c5d0bb6b..599e0dfb 100644 --- a/wit/wasi.wit +++ b/wit/wasi.wit @@ -11,7 +11,7 @@ interface command { args: list, env-vars: list>, preopens: list> - ) + ) -> result } interface wasi-exit {