diff --git a/crates/wasi/src/preview2/preview1.rs b/crates/wasi/src/preview2/preview1.rs index 282f50ae75f6..ab5a9cbd59a1 100644 --- a/crates/wasi/src/preview2/preview1.rs +++ b/crates/wasi/src/preview2/preview1.rs @@ -9,7 +9,7 @@ use crate::preview2::bindings::{ io::{poll, streams}, }; use crate::preview2::{FsError, IsATTY, StreamError, StreamResult, TableError, WasiView}; -use anyhow::{anyhow, bail, Context}; +use anyhow::{bail, Context}; use std::borrow::Borrow; use std::collections::{BTreeMap, HashSet}; use std::mem::{self, size_of, size_of_val}; @@ -1131,6 +1131,9 @@ impl< .map_err(types::Error::trap)?; let mut fs_flags = types::Fdflags::empty(); let mut fs_rights_base = types::Rights::all(); + if let types::Filetype::Directory = fs_filetype { + fs_rights_base &= !types::Rights::FD_SEEK; + } if !flags.contains(filesystem::DescriptorFlags::READ) { fs_rights_base &= !types::Rights::FD_READ; } @@ -2258,14 +2261,11 @@ impl< #[instrument(skip(self))] fn proc_exit(&mut self, status: types::Exitcode) -> anyhow::Error { - let status = match status { - 0 => Ok(()), - _ => Err(()), - }; - match self.exit(status) { - Err(e) => e, - Ok(()) => anyhow!("`exit` did not return an error"), + // Check that the status is within WASI's range. + if status >= 126 { + return anyhow::Error::msg("exit with invalid exit status outside of [0..126)"); } + crate::preview2::I32Exit(status as i32).into() } #[instrument(skip(self))] diff --git a/src/commands/run.rs b/src/commands/run.rs index df2fd673de72..944c9434eec8 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -584,14 +584,22 @@ impl RunCommand { if self.run.common.wasi.common != Some(false) { match linker { CliLinker::Core(linker) => { - if self.run.common.wasi.preview2 == Some(true) { - preview2::preview1::add_to_linker_sync(linker)?; - self.set_preview2_ctx(store)?; - } else { - wasmtime_wasi::add_to_linker(linker, |host| { - host.preview1_ctx.as_mut().unwrap() - })?; - self.set_preview1_ctx(store)?; + match (self.run.common.wasi.preview2, self.run.common.wasi.threads) { + // If preview2 is explicitly disabled, or if threads + // are enabled, then use the historical preview1 + // implementation. + (Some(false), _) | (None, Some(true)) => { + wasmtime_wasi::add_to_linker(linker, |host| { + host.preview1_ctx.as_mut().unwrap() + })?; + self.set_preview1_ctx(store)?; + } + // If preview2 was explicitly requested, always use it. + // Otherwise use it so long as threads are disabled. + (Some(true), _) | (None, Some(false) | None) => { + preview2::preview1::add_to_linker_sync(linker)?; + self.set_preview2_ctx(store)?; + } } } #[cfg(feature = "component-model")] diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs index 2c8aa81222a1..39d435d9d147 100644 --- a/tests/all/cli_tests.rs +++ b/tests/all/cli_tests.rs @@ -184,7 +184,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(&["-Ccache=n", wasm.path().to_str().unwrap()])?; + let stdout = run_wasmtime(&["-Ccache=n", "-Spreview2=n", wasm.path().to_str().unwrap()])?; assert_eq!(stdout, "Hello, world!\n"); Ok(()) } @@ -248,7 +248,10 @@ fn timeout_in_invoke() -> Result<()> { #[test] fn exit2_wasi_snapshot0() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/exit2_wasi_snapshot0.wat")?; - let output = run_wasmtime_for_output(&["-Ccache=n", wasm.path().to_str().unwrap()], None)?; + let output = run_wasmtime_for_output( + &["-Ccache=n", "-Spreview2=n", wasm.path().to_str().unwrap()], + None, + )?; assert_eq!(output.status.code().unwrap(), 2); Ok(()) } @@ -266,7 +269,10 @@ fn exit2_wasi_snapshot1() -> Result<()> { #[test] fn exit125_wasi_snapshot0() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/exit125_wasi_snapshot0.wat")?; - let output = run_wasmtime_for_output(&["-Ccache=n", wasm.path().to_str().unwrap()], None)?; + let output = run_wasmtime_for_output( + &["-Ccache=n", "-Spreview2=n", wasm.path().to_str().unwrap()], + None, + )?; if cfg!(windows) { assert_eq!(output.status.code().unwrap(), 1); } else { @@ -292,7 +298,10 @@ fn exit125_wasi_snapshot1() -> Result<()> { #[test] fn exit126_wasi_snapshot0() -> Result<()> { let wasm = build_wasm("tests/all/cli_tests/exit126_wasi_snapshot0.wat")?; - let output = run_wasmtime_for_output(&["-Ccache=n", wasm.path().to_str().unwrap()], None)?; + let output = run_wasmtime_for_output( + &["-Ccache=n", "-Spreview2=n", wasm.path().to_str().unwrap()], + None, + )?; assert_eq!(output.status.code().unwrap(), 1); assert!(output.stdout.is_empty()); assert!(String::from_utf8_lossy(&output.stderr).contains("invalid exit status")); @@ -439,7 +448,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] = &["-Ccache=n", "-"]; + let args: &[&str] = &["-Ccache=n", "-Spreview2=n", "-"]; let output = run_wasmtime_for_output(args, Some(path))?; if !output.status.success() { bail!(