diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c7213eecc3c..d3a538ed7a5 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -128,6 +128,24 @@ jobs: - name: make build-wasmer-wasm run: make build-wasmer-wasm + test_build_jsc: + name: Test JSC build + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.65 + target: x86_64-unknown-linux-gnu + - name: Install NodeJS + uses: actions/setup-node@v2 + with: + node-version: 16 + - name: Install libjavascriptcoregtk-4.0-dev + run: sudo apt update && sudo apt install -y libjavascriptcoregtk-4.0-dev + - name: make build-wasmer-jsc + run: make build-wasmer-jsc + test_build_docs_rs: name: Test build docs rs runs-on: ubuntu-22.04 @@ -140,7 +158,7 @@ jobs: - run: cargo install toml-cli # toml-cli is required to run `make test-build-docs-rs` - name: make test-build-docs-rs run: make test-build-docs-rs - + build_linux_aarch64: name: ${{ matrix.build-what.name }} on linux-aarch64 runs-on: ubuntu-22.04 diff --git a/Cargo.lock b/Cargo.lock index b12bfb4e3cd..1cfe44ce01d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5387,6 +5387,7 @@ version = "3.3.0" dependencies = [ "anyhow", "atty", + "bytes", "bytesize", "cargo_metadata", "cfg-if 1.0.0", diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index bc2761884de..c20b7527d22 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -135,8 +135,7 @@ impl Memory { }); } self.0 - .try_clone(&store) - .and_then(|mut memory| memory.copy().ok()) + .try_copy(&store) .map(|new_memory| Self::new_from_existing(new_store, new_memory.into())) .ok_or_else(|| { MemoryError::Generic("memory is not clonable or could not be copied".to_string()) @@ -178,7 +177,7 @@ impl Memory { /// Attempts to clone this memory (if its clonable) in a new store /// (cloned memory will be shared between those that clone it) - #[deprecated = "use `shared_in_store` or `copy_to_store` instead"] + #[deprecated = "use `share_in_store` or `copy_to_store` instead"] pub fn duplicate_in_store( &self, store: &impl AsStoreRef, diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index a33645c3c60..3e9084521fd 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -140,11 +140,19 @@ impl Memory { Self { handle: internal } } + /// Cloning memory will create another reference to the same memory that + /// can be put into a new store pub fn try_clone(&self, _store: &impl AsStoreRef) -> Option { self.handle.try_clone() } - #[deprecated = "use `try_clone` instead"] + /// Copying the memory will actually copy all the bytes in the memory to + /// a identical byte copy of the original that can be put into a new store + pub fn try_copy(&self, store: &impl AsStoreRef) -> Option { + self.try_clone(store).and_then(|mut mem| mem.copy().ok()) + } + + #[deprecated = "use `try_clone` and `try_copy` instead"] pub fn duplicate_in_store( &self, store: &impl AsStoreRef, diff --git a/lib/api/src/jsc/externals/memory.rs b/lib/api/src/jsc/externals/memory.rs index f0923eb4295..af198db92f6 100644 --- a/lib/api/src/jsc/externals/memory.rs +++ b/lib/api/src/jsc/externals/memory.rs @@ -170,10 +170,30 @@ impl Memory { Self { handle: internal } } + /// Cloning memory will create another reference to the same memory that + /// can be put into a new store pub fn try_clone(&self, _store: &impl AsStoreRef) -> Option { self.handle.try_clone() } + /// Copying the memory will actually copy all the bytes in the memory to + /// a identical byte copy of the original that can be put into a new store + pub fn try_copy(&self, store: &impl AsStoreRef) -> Option { + self.try_clone(store) + .and_then(|mut mem| mem.copy(store).ok()) + } + + #[deprecated = "use `try_clone` and `try_copy` instead"] + pub fn duplicate_in_store( + &self, + store: &impl AsStoreRef, + new_store: &mut impl AsStoreMut, + ) -> Option { + self.try_clone(&store) + .and_then(|mut memory| memory.duplicate(&store).ok()) + .map(|new_memory| Self::new_from_existing(new_store, new_memory.into())) + } + pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { true } diff --git a/lib/api/src/jsc/externals/memory_view.rs b/lib/api/src/jsc/externals/memory_view.rs index 73a747839ae..eb3e3515477 100644 --- a/lib/api/src/jsc/externals/memory_view.rs +++ b/lib/api/src/jsc/externals/memory_view.rs @@ -23,11 +23,11 @@ pub struct MemoryView<'a> { } impl<'a> MemoryView<'a> { - pub(crate) fn new(memory: &Memory, store: &'a impl AsStoreRef) -> Self { + pub(crate) fn new(memory: &Memory, store: &'a (impl AsStoreRef + ?Sized)) -> Self { Self::new_raw(&memory.handle.memory, store) } - pub(crate) fn new_raw(memory: &JSObject, store: &'a impl AsStoreRef) -> Self { + pub(crate) fn new_raw(memory: &JSObject, store: &'a (impl AsStoreRef + ?Sized)) -> Self { let store_ref = store.as_store_ref(); let engine = store_ref.engine(); let context = engine.0.context(); diff --git a/lib/api/src/jsc/vm.rs b/lib/api/src/jsc/vm.rs index 9100300971a..067717bd3a5 100644 --- a/lib/api/src/jsc/vm.rs +++ b/lib/api/src/jsc/vm.rs @@ -50,10 +50,16 @@ impl VMMemory { } /// Copies this memory to a new memory + #[deprecated = "use `copy` instead"] pub fn duplicate( - &self, + &mut self, store: &impl AsStoreRef, ) -> Result { + self.copy(store) + } + + /// Copies this memory to a new memory + pub fn copy(&self, store: &impl AsStoreRef) -> Result { let new_memory = crate::jsc::externals::memory::Memory::js_memory_from_type(&store, &self.ty)?; diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index f09a8453e85..c830273ad4d 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -63,12 +63,20 @@ impl Memory { self.handle.store_id() == store.as_store_ref().objects().id() } + /// Cloning memory will create another reference to the same memory that + /// can be put into a new store pub fn try_clone(&self, store: &impl AsStoreRef) -> Option { let mem = self.handle.get(store.as_store_ref().objects()); mem.try_clone().map(|mem| mem.into()) } - #[deprecated = "use `try_clone` instead"] + /// Copying the memory will actually copy all the bytes in the memory to + /// a identical byte copy of the original that can be put into a new store + pub fn try_copy(&self, store: &impl AsStoreRef) -> Option> { + self.try_clone(store).and_then(|mut mem| mem.copy().ok()) + } + + #[deprecated = "use `try_clone` and `try_copy` instead"] pub fn duplicate_in_store( &self, store: &impl AsStoreRef, diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index 467d583a633..542b86215f9 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -72,6 +72,7 @@ hex = "0.4.3" flate2 = "1.0.25" cargo_metadata = "0.15.2" tar = "0.4.38" +bytes = "1" thiserror = "1.0.37" log = "0.4.17" semver = "1.0.14" diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index 1ca9cd55d92..6b0f047bb72 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -350,7 +350,7 @@ impl RunWithPathBuf { .instantiate(&mut store, &module, program_name, self.args.clone()) .with_context(|| "failed to instantiate WASI module")?; - let capable_of_deep_sleep = ctx.data(&store).capable_of_deep_sleep(); + let capable_of_deep_sleep = unsafe { ctx.data(&store).capable_of_deep_sleep() }; ctx.data_mut(&mut store) .enable_deep_sleep = capable_of_deep_sleep; diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 893c0a613ef..a3a76a7e38c 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -1,5 +1,7 @@ +use crate::anyhow::Context; use crate::utils::{parse_envvar, parse_mapdir}; -use anyhow::{Context, Result}; +use anyhow::Result; +use bytes::Bytes; use std::{ collections::{BTreeSet, HashMap}, path::{Path, PathBuf}, @@ -14,7 +16,7 @@ use wasmer_wasix::{ bin_factory::BinaryPackage, default_fs_backing, get_wasi_versions, os::{tty_sys::SysTty, TtyBridge}, - rewind, + rewind_ext, runners::MappedDirectory, runtime::{ module_cache::{FileSystemCache, ModuleCache}, @@ -294,40 +296,30 @@ impl Wasi { run: RunProperties, mut store: Store, tx: Sender>, - rewind_state: Option<(RewindState, Result<(), Errno>)>, + rewind_state: Option<(RewindState, Bytes)>, ) { // If we need to rewind then do so let ctx = run.ctx; - if let Some((mut rewind_state, trigger_res)) = rewind_state { + if let Some((rewind_state, rewind_result)) = rewind_state { if rewind_state.is_64bit { - if let Err(exit_code) = - rewind_state.rewinding_finish::(&ctx, &mut store, trigger_res) - { - tx.send(Ok(exit_code.raw())).ok(); - return; - } - let res = rewind::( + let res = rewind_ext::( ctx.env.clone().into_mut(&mut store), rewind_state.memory_stack, rewind_state.rewind_stack, rewind_state.store_data, + rewind_result, ); if res != Errno::Success { tx.send(Ok(res as i32)).ok(); return; } } else { - if let Err(exit_code) = - rewind_state.rewinding_finish::(&ctx, &mut store, trigger_res) - { - tx.send(Ok(exit_code.raw())).ok(); - return; - } - let res = rewind::( + let res = rewind_ext::( ctx.env.clone().into_mut(&mut store), rewind_state.memory_stack, rewind_state.rewind_stack, rewind_state.store_data, + rewind_result, ); if res != Errno::Success { tx.send(Ok(res as i32)).ok(); @@ -416,9 +408,15 @@ impl Wasi { }; // Spawns the WASM process after a trigger - tasks - .resume_wasm_after_poller(Box::new(respawn), ctx, store, deep.trigger) - .unwrap(); + unsafe { + tasks.resume_wasm_after_poller( + Box::new(respawn), + ctx, + store, + deep.trigger, + ) + } + .unwrap(); return; } Ok(err) => Err(err.into()), diff --git a/lib/wasi-types/src/wasi/bindings.rs b/lib/wasi-types/src/wasi/bindings.rs index fff5ac48d60..afe583a1e9a 100644 --- a/lib/wasi-types/src/wasi/bindings.rs +++ b/lib/wasi-types/src/wasi/bindings.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; use std::mem::MaybeUninit; use wasmer::{MemorySize, ValueType}; // TODO: Remove once bindings generate wai_bindgen_rust::bitflags::bitflags! (temp hack) @@ -93,6 +95,7 @@ impl core::fmt::Debug for Clockid { #[doc = " merely for alignment with POSIX."] #[repr(u16)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum Errno { #[doc = " No error occurred. System call completed successfully."] Success, @@ -875,6 +878,7 @@ pub type Userdata = u64; #[doc = " Type of a subscription to an event or its occurrence."] #[repr(u8)] #[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum Eventtype { #[doc = " The time value of clock `subscription_clock::id` has"] #[doc = " reached timestamp `subscription_clock::timeout`."] @@ -982,6 +986,7 @@ impl core::fmt::Debug for Preopentype { wai_bindgen_rust::bitflags::bitflags! { #[doc = " The state of the file descriptor subscribed to with"] #[doc = " `eventtype::fd_read` or `eventtype::fd_write`."] + #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Eventrwflags : u16 { #[doc = " The peer of this socket has closed or disconnected."] const FD_READWRITE_HANGUP = 1 << 0; @@ -998,6 +1003,7 @@ impl Eventrwflags { #[doc = " `eventtype::fd_write` variants"] #[repr(C)] #[derive(Copy, Clone)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct EventFdReadwrite { #[doc = " The number of bytes available for reading or writing."] pub nbytes: Filesize, diff --git a/lib/wasi-types/src/wasi/wasix_manual.rs b/lib/wasi-types/src/wasi/wasix_manual.rs index c33465221eb..8f0b21d5f86 100644 --- a/lib/wasi-types/src/wasi/wasix_manual.rs +++ b/lib/wasi-types/src/wasi/wasix_manual.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; use std::mem::MaybeUninit; use wasmer::{FromToNativeWasmType, MemorySize, ValueType}; @@ -179,7 +181,7 @@ unsafe impl ValueType for StackSnapshot { #[repr(C)] #[derive(Clone, Copy)] pub union JoinStatusUnion { - pub nothing_errno: Errno, + pub nothing: u8, pub exit_normal: Errno, pub exit_signal: ErrnoSignal, pub stopped: Signal, @@ -196,7 +198,7 @@ impl core::fmt::Debug for JoinStatus { let mut f = binding.field("tag", &self.tag); f = unsafe { match self.tag { - JoinStatusType::Nothing => f.field("nothing_errno", &self.u.nothing_errno), + JoinStatusType::Nothing => f.field("nothing", &self.u.nothing), JoinStatusType::ExitNormal => f.field("exit_normal", &self.u.exit_normal), JoinStatusType::ExitSignal => f.field("exit_signal", &self.u.exit_signal), JoinStatusType::Stopped => f.field("stopped", &self.u.stopped), @@ -242,6 +244,7 @@ unsafe impl ValueType for ThreadStart { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum ExitCode { Errno(Errno), Other(i32), diff --git a/lib/wasi-web/Cargo.lock b/lib/wasi-web/Cargo.lock index f86357bc294..f5a16f7624f 100644 --- a/lib/wasi-web/Cargo.lock +++ b/lib/wasi-web/Cargo.lock @@ -2305,6 +2305,7 @@ dependencies = [ "indexmap", "more-asserts", "rkyv", + "serde", "target-lexicon", "thiserror", ] @@ -2391,6 +2392,7 @@ dependencies = [ "byteorder", "cfg-if", "num_enum", + "serde", "time", "wai-bindgen-gen-core", "wai-bindgen-gen-rust", diff --git a/lib/wasi-web/src/pool.rs b/lib/wasi-web/src/pool.rs index 0987dc462cd..8667d551618 100644 --- a/lib/wasi-web/src/pool.rs +++ b/lib/wasi-web/src/pool.rs @@ -36,6 +36,7 @@ use wasmer_wasix::{ }, SpawnMemoryType, }, + types::wasi::ExitCode, wasmer::{AsJs, Memory, MemoryType, Module, Store, WASM_MAX_PAGES}, wasmer_wasix_types::wasi::Errno, InstanceSnapshot, VirtualTaskManager, WasiEnv, WasiFunctionEnv, WasiThreadError, @@ -79,7 +80,7 @@ struct WasmRunCommand { snapshot: Option, trigger: Option, update_layout: bool, - result: Result<(), Errno>, + result: Option>, } trait AssertSendSync: Send + Sync {} @@ -320,7 +321,7 @@ impl WebThreadPool { module_bytes, snapshot, update_layout, - result: Ok(()), + result: None, }); let task = Box::into_raw(task); @@ -687,7 +688,7 @@ pub fn schedule_wasm_task( wasm_bindgen_futures::spawn_local(async move { if let Some(trigger) = trigger { let run = trigger.run; - task.result = run().await; + task.result = Some(run().await); } let task = Box::into_raw(task); diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 1142bffc2b5..900f2ae64c0 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -15,7 +15,7 @@ cfg-if = "1.0" thiserror = "1" tracing = { version = "0.1" } getrandom = "0.2" -wasmer-wasix-types = { path = "../wasi-types", version = "0.4.0" } +wasmer-wasix-types = { path = "../wasi-types", version = "0.4.0", features = [ "enable-serde" ] } wasmer-types = { path = "../types", version = "=3.3.0", default-features = false } wasmer = { path = "../api", version = "=3.3.0", default-features = false, features = ["wat", "js-serializable-module"] } virtual-fs = { path = "../vfs", version = "0.2.0", default-features = false, features = ["webc-fs"] } diff --git a/lib/wasi/src/bin_factory/exec.rs b/lib/wasi/src/bin_factory/exec.rs index 1cf3c6656f9..c11cfaec9be 100644 --- a/lib/wasi/src/bin_factory/exec.rs +++ b/lib/wasi/src/bin_factory/exec.rs @@ -3,9 +3,10 @@ use std::{pin::Pin, sync::Arc}; use crate::{ os::task::{thread::WasiThreadRunGuard, TaskJoinHandle}, runtime::task_manager::{TaskWasm, TaskWasmRunProperties}, - syscalls::rewind, + syscalls::rewind_ext, RewindState, VirtualBusError, WasiError, WasiRuntimeError, }; +use bytes::Bytes; use futures::Future; use tracing::*; use wasmer::{Function, FunctionEnvMut, Memory32, Memory64, Module, Store}; @@ -105,9 +106,7 @@ pub fn spawn_exec_module( // Perform the initialization let ctx = { // If this module exports an _initialize function, run that first. - if let Ok(initialize) = ctx - .data(&store) - .inner() + if let Ok(initialize) = unsafe { ctx.data(&store).inner() } .instance .exports .get_function("_initialize") @@ -145,8 +144,7 @@ pub fn spawn_exec_module( } fn get_start(ctx: &WasiFunctionEnv, store: &Store) -> Option { - ctx.data(store) - .inner() + unsafe { ctx.data(store).inner() } .instance .exports .get_function("_start") @@ -159,7 +157,7 @@ fn call_module( ctx: WasiFunctionEnv, mut store: Store, handle: WasiThreadRunGuard, - rewind_state: Option<(RewindState, Result<(), Errno>)>, + rewind_state: Option<(RewindState, Bytes)>, ) { let env = ctx.data(&store); let pid = env.pid(); @@ -167,36 +165,26 @@ fn call_module( handle.thread.set_status_running(); // If we need to rewind then do so - if let Some((mut rewind_state, trigger_res)) = rewind_state { + if let Some((rewind_state, rewind_result)) = rewind_state { if rewind_state.is_64bit { - if let Err(exit_code) = - rewind_state.rewinding_finish::(&ctx, &mut store, trigger_res) - { - ctx.data(&store).blocking_cleanup(Some(exit_code)); - return; - } - let res = rewind::( + let res = rewind_ext::( ctx.env.clone().into_mut(&mut store), rewind_state.memory_stack, rewind_state.rewind_stack, rewind_state.store_data, + rewind_result, ); if res != Errno::Success { ctx.data(&store).blocking_cleanup(Some(res.into())); return; } } else { - if let Err(exit_code) = - rewind_state.rewinding_finish::(&ctx, &mut store, trigger_res) - { - ctx.data(&store).blocking_cleanup(Some(exit_code)); - return; - } - let res = rewind::( + let res = rewind_ext::( ctx.env.clone().into_mut(&mut store), rewind_state.memory_stack, rewind_state.rewind_stack, rewind_state.store_data, + rewind_result, ); if res != Errno::Success { ctx.data(&store).blocking_cleanup(Some(res.into())); @@ -230,16 +218,16 @@ fn call_module( // Create the callback that will be invoked when the thread respawns after a deep sleep let rewind = deep.rewind; let respawn = { - move |ctx, store, trigger_res| { + move |ctx, store, rewind_result| { // Call the thread - call_module(ctx, store, handle, Some((rewind, trigger_res))); + call_module(ctx, store, handle, Some((rewind, rewind_result))); } }; // Spawns the WASM process after a trigger - if let Err(err) = + if let Err(err) = unsafe { tasks.resume_wasm_after_poller(Box::new(respawn), ctx, store, deep.trigger) - { + } { debug!("failed to go into deep sleep - {}", err); } return; diff --git a/lib/wasi/src/fs/inode_guard.rs b/lib/wasi/src/fs/inode_guard.rs index 56a30d19d86..e357d6609c7 100644 --- a/lib/wasi/src/fs/inode_guard.rs +++ b/lib/wasi/src/fs/inode_guard.rs @@ -14,14 +14,14 @@ use virtual_net::NetworkError; use wasmer_wasix_types::{ types::Eventtype, wasi, - wasi::{Errno, Event, EventFdReadwrite, EventUnion, Eventrwflags, Subscription}, + wasi::{Errno, EventFdReadwrite, Eventrwflags, Subscription}, }; use super::{notification::NotificationInner, InodeGuard, Kind}; use crate::{ net::socket::{InodeSocketInner, InodeSocketKind}, state::{iterate_poll_events, PollEvent, PollEventSet, WasiState}, - syscalls::map_io_err, + syscalls::{map_io_err, EventResult, EventResultType}, utils::{OwnedRwLockReadGuard, OwnedRwLockWriteGuard}, }; @@ -133,7 +133,7 @@ impl InodeValFilePollGuardJoin { } impl Future for InodeValFilePollGuardJoin { - type Output = heapless::Vec; + type Output = heapless::Vec; fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { let fd = self.fd(); @@ -198,22 +198,22 @@ impl Future for InodeValFilePollGuardJoin { } }; if is_closed { - ret.push(Event { + ret.push(EventResult { userdata: self.subscription.userdata, error: Errno::Success, type_: self.subscription.type_, - u: match self.subscription.type_ { - Eventtype::FdRead | Eventtype::FdWrite => EventUnion { - fd_readwrite: EventFdReadwrite { + inner: match self.subscription.type_ { + Eventtype::FdRead | Eventtype::FdWrite => { + EventResultType::Fd(EventFdReadwrite { nbytes: 0, flags: if has_hangup { Eventrwflags::FD_READWRITE_HANGUP } else { Eventrwflags::empty() }, - }, - }, - Eventtype::Clock => EventUnion { clock: 0 }, + }) + } + Eventtype::Clock => EventResultType::Clock(0), }, }) .ok(); @@ -260,22 +260,22 @@ impl Future for InodeValFilePollGuardJoin { }; match poll_result { Poll::Ready(Err(err)) if has_close && is_err_closed(&err) => { - ret.push(Event { + ret.push(EventResult { userdata: self.subscription.userdata, error: Errno::Success, type_: self.subscription.type_, - u: match self.subscription.type_ { - Eventtype::FdRead | Eventtype::FdWrite => EventUnion { - fd_readwrite: EventFdReadwrite { + inner: match self.subscription.type_ { + Eventtype::FdRead | Eventtype::FdWrite => { + EventResultType::Fd(EventFdReadwrite { nbytes: 0, flags: if has_hangup { Eventrwflags::FD_READWRITE_HANGUP } else { Eventrwflags::empty() }, - }, - }, - Eventtype::Clock => EventUnion { clock: 0 }, + }) + } + Eventtype::Clock => EventResultType::Clock(0), }, }) .ok(); @@ -289,22 +289,22 @@ impl Future for InodeValFilePollGuardJoin { 0 } }; - ret.push(Event { + ret.push(EventResult { userdata: self.subscription.userdata, error, type_: self.subscription.type_, - u: match self.subscription.type_ { - Eventtype::FdRead | Eventtype::FdWrite => EventUnion { - fd_readwrite: EventFdReadwrite { + inner: match self.subscription.type_ { + Eventtype::FdRead | Eventtype::FdWrite => { + EventResultType::Fd(EventFdReadwrite { nbytes: bytes_available as u64, flags: if bytes_available == 0 { Eventrwflags::FD_READWRITE_HANGUP } else { Eventrwflags::empty() }, - }, - }, - Eventtype::Clock => EventUnion { clock: 0 }, + }) + } + Eventtype::Clock => EventResultType::Clock(0), }, }) .ok(); @@ -353,22 +353,22 @@ impl Future for InodeValFilePollGuardJoin { }; match poll_result { Poll::Ready(Err(err)) if has_close && is_err_closed(&err) => { - ret.push(Event { + ret.push(EventResult { userdata: self.subscription.userdata, error: Errno::Success, type_: self.subscription.type_, - u: match self.subscription.type_ { - Eventtype::FdRead | Eventtype::FdWrite => EventUnion { - fd_readwrite: EventFdReadwrite { + inner: match self.subscription.type_ { + Eventtype::FdRead | Eventtype::FdWrite => { + EventResultType::Fd(EventFdReadwrite { nbytes: 0, flags: if has_hangup { Eventrwflags::FD_READWRITE_HANGUP } else { Eventrwflags::empty() }, - }, - }, - Eventtype::Clock => EventUnion { clock: 0 }, + }) + } + Eventtype::Clock => EventResultType::Clock(0), }, }) .ok(); @@ -382,22 +382,22 @@ impl Future for InodeValFilePollGuardJoin { 0 } }; - ret.push(Event { + ret.push(EventResult { userdata: self.subscription.userdata, error, type_: self.subscription.type_, - u: match self.subscription.type_ { - Eventtype::FdRead | Eventtype::FdWrite => EventUnion { - fd_readwrite: EventFdReadwrite { + inner: match self.subscription.type_ { + Eventtype::FdRead | Eventtype::FdWrite => { + EventResultType::Fd(EventFdReadwrite { nbytes: bytes_available as u64, flags: if bytes_available == 0 { Eventrwflags::FD_READWRITE_HANGUP } else { Eventrwflags::empty() }, - }, - }, - Eventtype::Clock => EventUnion { clock: 0 }, + }) + } + Eventtype::Clock => EventResultType::Clock(0), }, }) .ok(); diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 177688ff491..e9a5d7fdc89 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -53,9 +53,6 @@ pub use rewind::*; /// WAI based bindings. mod bindings; -use std::sync::Arc; -use std::{cell::RefCell, sync::atomic::AtomicU32}; - #[allow(unused_imports)] use bytes::{Bytes, BytesMut}; use os::task::control_plane::ControlPlaneError; @@ -109,7 +106,7 @@ pub use crate::{ WasiEnv, WasiEnvBuilder, WasiEnvInit, WasiFunctionEnv, WasiInstanceHandles, WasiStateCreationError, ALL_RIGHTS, }, - syscalls::{rewind, types, unwind}, + syscalls::{rewind, rewind_ext, types, unwind}, utils::{ get_wasi_version, get_wasi_versions, is_wasi_module, store::{capture_snapshot, restore_snapshot, InstanceSnapshot}, @@ -271,10 +268,6 @@ pub struct WasiVFork { pub memory_stack: BytesMut, /// The mutable parts of the store pub store_data: Bytes, - /// Offset into the memory where the PID will be - /// written when the real fork takes places - pub pid_offset: u64, - /// The environment before the vfork occured pub env: Box, @@ -289,20 +282,12 @@ impl Clone for WasiVFork { rewind_stack: self.rewind_stack.clone(), memory_stack: self.memory_stack.clone(), store_data: self.store_data.clone(), - pid_offset: self.pid_offset, env: Box::new(self.env.as_ref().clone()), handle: self.handle.clone(), } } } -// Represents the current thread ID for the executing method -thread_local!(pub(crate) static CALLER_ID: RefCell = RefCell::new(0)); -thread_local!(pub(crate) static REWIND: RefCell> = RefCell::new(None)); -lazy_static::lazy_static! { - static ref CALLER_ID_SEED: Arc = Arc::new(AtomicU32::new(1)); -} - /// Create an [`Imports`] with an existing [`WasiEnv`]. `WasiEnv` /// needs a [`WasiState`], that can be constructed from a /// [`WasiEnvBuilder`](state::WasiEnvBuilder). diff --git a/lib/wasi/src/os/command/builtins/cmd_wasmer.rs b/lib/wasi/src/os/command/builtins/cmd_wasmer.rs index c5533a61c8b..ee6c3684755 100644 --- a/lib/wasi/src/os/command/builtins/cmd_wasmer.rs +++ b/lib/wasi/src/os/command/builtins/cmd_wasmer.rs @@ -75,17 +75,19 @@ impl CmdWasmer { // Now run the module spawn_exec(binary, name, store, env, &self.runtime).await } else { - let _ = stderr_write( - parent_ctx, - format!("package not found - {}\r\n", what).as_bytes(), - ) + let _ = unsafe { + stderr_write( + parent_ctx, + format!("package not found - {}\r\n", what).as_bytes(), + ) + } .await; let handle = OwnedTaskStatus::new_finished_with_code(Errno::Noent.into()).handle(); Ok(handle) } // Get the binary } else { - let _ = stderr_write(parent_ctx, HELP_RUN.as_bytes()).await; + let _ = unsafe { stderr_write(parent_ctx, HELP_RUN.as_bytes()) }.await; let handle = OwnedTaskStatus::new_finished_with_code(Errno::Success.into()).handle(); Ok(handle) } @@ -132,7 +134,7 @@ impl VirtualCommand for CmdWasmer { } Some("--help") | None => { parent_ctx.data().tasks().block_on(async move { - let _ = stderr_write(parent_ctx, HELP.as_bytes()).await; + let _ = unsafe { stderr_write(parent_ctx, HELP.as_bytes()) }.await; }); let handle = OwnedTaskStatus::new_finished_with_code(Errno::Success.into()).handle(); diff --git a/lib/wasi/src/os/command/mod.rs b/lib/wasi/src/os/command/mod.rs index d8c65a5833a..218c2c3e50b 100644 --- a/lib/wasi/src/os/command/mod.rs +++ b/lib/wasi/src/os/command/mod.rs @@ -91,10 +91,12 @@ impl Commands { if let Some(cmd) = self.commands.get(&path) { cmd.exec(parent_ctx, path.as_str(), store, builder) } else { - let _ = stderr_write( - parent_ctx, - format!("wasm command unknown - {}\r\n", path).as_bytes(), - ); + unsafe { + let _ = stderr_write( + parent_ctx, + format!("wasm command unknown - {}\r\n", path).as_bytes(), + ); + } let res = OwnedTaskStatus::new(TaskStatus::Finished(Ok(Errno::Noent.into()))); Ok(res.handle()) diff --git a/lib/wasi/src/os/task/process.rs b/lib/wasi/src/os/task/process.rs index 5eb3a9e9869..5dc8f6d26e5 100644 --- a/lib/wasi/src/os/task/process.rs +++ b/lib/wasi/src/os/task/process.rs @@ -1,3 +1,5 @@ +use crate::WasiRuntimeError; +use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, convert::TryInto, @@ -7,8 +9,6 @@ use std::{ }, time::Duration, }; - -use crate::WasiRuntimeError; use tracing::trace; use wasmer_wasix_types::{ types::Signal, @@ -27,7 +27,7 @@ use super::{ }; /// Represents the ID of a sub-process -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct WasiProcessId(u32); impl WasiProcessId { diff --git a/lib/wasi/src/os/task/thread.rs b/lib/wasi/src/os/task/thread.rs index 15fef9f4bfd..dd6d21e6b31 100644 --- a/lib/wasi/src/os/task/thread.rs +++ b/lib/wasi/src/os/task/thread.rs @@ -95,6 +95,21 @@ pub struct ThreadStack { #[derive(Clone, Debug)] pub struct WasiThread { state: Arc, + + // This is used for stack rewinds + rewind: Option, +} + +impl WasiThread { + /// Sets that a rewind will take place + pub(crate) fn set_rewind(&mut self, rewind: RewindResult) { + self.rewind.replace(rewind); + } + + /// Pops any rewinds that need to take place + pub(crate) fn take_rewind(&mut self) -> Option { + self.rewind.take() + } } /// A guard that ensures a thread is marked as terminated when dropped. @@ -123,7 +138,7 @@ impl Drop for WasiThreadRunGuard { } /// Represents the memory layout of the parts that the thread itself uses -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct WasiMemoryLayout { /// This is the top part of the stack (stacks go backwards) pub stack_upper: u64, @@ -137,19 +152,14 @@ pub struct WasiMemoryLayout { pub stack_size: u64, } -/// The default stack size for WASIX -pub const DEFAULT_STACK_SIZE: u64 = 1_048_576u64; -pub const DEFAULT_STACK_BASE: u64 = DEFAULT_STACK_SIZE; - -impl Default for WasiMemoryLayout { - fn default() -> Self { - Self { - stack_lower: 0, - stack_upper: DEFAULT_STACK_SIZE, - guard_size: 0, - stack_size: DEFAULT_STACK_SIZE, - } - } +// Contains the result of a rewind operation +#[derive(Clone, Debug)] +pub(crate) struct RewindResult { + /// Memory stack used to restore the stack trace back to where it was + pub memory_stack: Bytes, + /// Generic serialized object passed back to the rewind resumption code + /// (uses the bincode serializer) + pub rewind_result: Bytes, } #[derive(Debug)] @@ -186,6 +196,7 @@ impl WasiThread { stack: Mutex::new(ThreadStack::default()), _task_count_guard: guard, }), + rewind: None, } } diff --git a/lib/wasi/src/rewind.rs b/lib/wasi/src/rewind.rs index b2bca34f1b6..2ad1fc2f4b4 100644 --- a/lib/wasi/src/rewind.rs +++ b/lib/wasi/src/rewind.rs @@ -2,33 +2,21 @@ use std::pin::Pin; use bytes::Bytes; use futures::Future; -use wasmer::{AsStoreMut, AsStoreRef, MemorySize}; -use wasmer_wasix_types::wasi::{Errno, ExitCode}; - -use crate::{ - syscalls::{get_memory_stack, set_memory_stack}, - WasiEnv, WasiFunctionEnv, -}; +use wasmer_wasix_types::wasi::Errno; /// Future that will be polled by asyncify methods #[doc(hidden)] -pub type AsyncifyFuture = dyn Future> + Send + Sync + 'static; +pub type AsyncifyFuture = dyn Future + Send + Sync + 'static; /// Trait that will be invoked after the rewind has finished /// It is possible that the process will be terminated rather /// than restored at this point -#[doc(hidden)] pub trait RewindPostProcess { - fn finish( - &mut self, - env: &WasiEnv, - store: &dyn AsStoreRef, - res: Result<(), Errno>, - ) -> Result<(), ExitCode>; + /// Returns the serialized object that is returned on the rewind + fn finish(&mut self, res: Result<(), Errno>) -> Bytes; } /// The rewind state after a deep sleep -#[doc(hidden)] pub struct RewindState { /// Memory stack used to restore the stack trace back to where it was pub memory_stack: Bytes, @@ -38,36 +26,6 @@ pub struct RewindState { pub store_data: Bytes, /// Flag that indicates if this rewind is 64-bit or 32-bit memory based pub is_64bit: bool, - /// This is the function that's invoked after the work is finished - /// and the rewind has been applied. - pub finish: Box, -} - -impl RewindState { - #[doc(hidden)] - pub fn rewinding_finish( - &mut self, - ctx: &WasiFunctionEnv, - store: &mut impl AsStoreMut, - res: Result<(), Errno>, - ) -> Result<(), ExitCode> { - let mut ctx = ctx.env.clone().into_mut(store); - let (env, mut store) = ctx.data_and_store_mut(); - set_memory_stack::(env, &mut store, self.memory_stack.clone()).map_err(|err| { - tracing::error!("failed on rewinding_finish - {}", err); - ExitCode::Errno(Errno::Memviolation) - })?; - let ret = self.finish.finish(env, &store, res); - if ret.is_ok() { - self.memory_stack = get_memory_stack::(env, &mut store) - .map_err(|err| { - tracing::error!("failed on rewinding_finish - {}", err); - ExitCode::Errno(Errno::Memviolation) - })? - .freeze(); - } - ret - } } /// Represents the work that will be done when a thread goes to deep sleep and diff --git a/lib/wasi/src/runtime/task_manager/mod.rs b/lib/wasi/src/runtime/task_manager/mod.rs index 9adadbe3b1d..7bb853bb796 100644 --- a/lib/wasi/src/runtime/task_manager/mod.rs +++ b/lib/wasi/src/runtime/task_manager/mod.rs @@ -7,6 +7,7 @@ use std::task::{Context, Poll}; use std::{pin::Pin, time::Duration}; use ::tokio::runtime::Handle; +use bytes::Bytes; use futures::Future; use wasmer::{AsStoreMut, AsStoreRef, Memory, MemoryType, Module, Store, StoreMut, StoreRef}; use wasmer_wasix_types::wasi::{Errno, ExitCode}; @@ -25,16 +26,20 @@ pub enum SpawnMemoryType<'a> { CopyMemory(Memory, StoreRef<'a>), } -pub type WasmResumeTask = dyn FnOnce(WasiFunctionEnv, Store, Result<(), Errno>) + Send + 'static; +pub type WasmResumeTask = dyn FnOnce(WasiFunctionEnv, Store, Bytes) + Send + 'static; -pub type WasmResumeTrigger = - dyn FnOnce() -> Pin> + Send + 'static>> + Send + Sync; +pub type WasmResumeTrigger = dyn FnOnce() -> Pin> + Send + 'static>> + + Send + + Sync; /// The properties passed to the task pub struct TaskWasmRunProperties { pub ctx: WasiFunctionEnv, pub store: Store, - pub result: Result<(), Errno>, + /// The result of the asynchronous trigger serialized into bytes using the bincode serializer + /// When no trigger is associated with the run operation (i.e. spawning threads) then this will be None. + /// (if the trigger returns an ExitCode then the WASM process will be terminated without resuming) + pub trigger_result: Option>, } /// Callback that will be invoked @@ -221,9 +226,9 @@ impl dyn VirtualTaskManager { /// Starts an WebAssembly task will will run on a dedicated thread /// pulled from the worker pool that has a stateful thread local variable - /// After the poller has successed + /// After the poller has succeeded #[doc(hidden)] - pub fn resume_wasm_after_poller( + pub unsafe fn resume_wasm_after_poller( &self, task: Box, ctx: WasiFunctionEnv, @@ -236,7 +241,7 @@ impl dyn VirtualTaskManager { trigger: Pin>, } impl Future for AsyncifyPollerOwned { - type Output = Result, ExitCode>; + type Output = Result; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let work = self.trigger.as_mut(); Poll::Ready(if let Poll::Ready(res) = work.poll(cx) { @@ -246,8 +251,6 @@ impl dyn VirtualTaskManager { tracing::debug!("exit runtime error - {}", err); Errno::Child.into() }))); - } else if self.thread.has_signals_or_subscribe(cx.waker()) { - Ok(Err(Errno::Intr)) } else { return Poll::Pending; }) @@ -261,9 +264,22 @@ impl dyn VirtualTaskManager { let thread = env.thread.clone(); let env = env.clone(); + let thread_inner = thread.clone(); self.task_wasm( TaskWasm::new( - Box::new(move |props| task(props.ctx, props.store, props.result)), + Box::new(move |props| { + let result = props + .trigger_result + .expect("If there is no result then its likely the trigger did not run"); + let result = match result { + Ok(r) => r, + Err(exit_code) => { + thread.set_status_finished(Ok(exit_code)); + return; + } + }; + task(props.ctx, props.store, result) + }), env.clone(), module, false, @@ -272,18 +288,21 @@ impl dyn VirtualTaskManager { .with_snapshot(&snapshot) .with_trigger(Box::new(move || { Box::pin(async move { - let mut poller = AsyncifyPollerOwned { thread, trigger }; + let mut poller = AsyncifyPollerOwned { + thread: thread_inner, + trigger, + }; let res = Pin::new(&mut poller).await; let res = match res { Ok(res) => res, Err(exit_code) => { env.thread.set_status_finished(Ok(exit_code)); - return Err(exit_code.into()); + return Err(exit_code); } }; tracing::trace!("deep sleep woken - {:?}", res); - res + Ok(res) }) })), ) diff --git a/lib/wasi/src/runtime/task_manager/tokio.rs b/lib/wasi/src/runtime/task_manager/tokio.rs index b84b93bfe81..8dfdd5f015b 100644 --- a/lib/wasi/src/runtime/task_manager/tokio.rs +++ b/lib/wasi/src/runtime/task_manager/tokio.rs @@ -131,14 +131,14 @@ impl VirtualTaskManager for TokioTaskManager { let trigger = trigger(); let handle = self.0.clone(); self.0.spawn(async move { - let res = trigger.await; + let result = trigger.await; // Build the task that will go on the callback handle.spawn_blocking(move || { // Invoke the callback run(TaskWasmRunProperties { ctx, store, - result: res, + trigger_result: Some(result), }); }); }); @@ -149,7 +149,7 @@ impl VirtualTaskManager for TokioTaskManager { run(TaskWasmRunProperties { ctx, store, - result: Ok(()), + trigger_result: None, }); }); } diff --git a/lib/wasi/src/state/env.rs b/lib/wasi/src/state/env.rs index 301bf70d7e5..362a08cf76a 100644 --- a/lib/wasi/src/state/env.rs +++ b/lib/wasi/src/state/env.rs @@ -387,7 +387,12 @@ impl WasiEnv { /// Returns true if this module is capable of deep sleep /// (needs asyncify to unwind and rewin) - pub fn capable_of_deep_sleep(&self) -> bool { + /// + /// # Safety + /// + /// This function should only be called from within a syscall + /// as it accessed objects that are a thread local (functions) + pub unsafe fn capable_of_deep_sleep(&self) -> bool { if !self.control_plane.config().enable_asynchronous_threading { return false; } @@ -554,13 +559,16 @@ impl WasiEnv { } /// Porcesses any signals that are batched up or any forced exit codes - pub fn process_signals_and_exit( + pub(crate) fn process_signals_and_exit( ctx: &mut FunctionEnvMut<'_, Self>, ) -> Result, WasiError> { // If a signal handler has never been set then we need to handle signals // differently let env = ctx.data(); - if !env.inner().signal_set { + let inner = env + .try_inner() + .ok_or_else(|| WasiError::Exit(Errno::Fault.into()))?; + if !inner.signal_set { let signals = env.thread.pop_signals(); let signal_cnt = signals.len(); for sig in signals { @@ -587,19 +595,22 @@ impl WasiEnv { } /// Porcesses any signals that are batched up - pub fn process_signals( + pub(crate) fn process_signals( ctx: &mut FunctionEnvMut<'_, Self>, ) -> Result, WasiError> { // If a signal handler has never been set then we need to handle signals // differently let env = ctx.data(); - if !env.inner().signal_set { + let inner = env + .try_inner() + .ok_or_else(|| WasiError::Exit(Errno::Fault.into()))?; + if !inner.signal_set { return Ok(Ok(false)); } // Check for any signals that we need to trigger // (but only if a signal handler is registered) - if env.inner().signal.as_ref().is_some() { + if inner.signal.as_ref().is_some() { let signals = env.thread.pop_signals(); Ok(Ok(Self::process_signals_internal(ctx, signals)?)) } else { @@ -607,12 +618,15 @@ impl WasiEnv { } } - pub fn process_signals_internal( + pub(crate) fn process_signals_internal( ctx: &mut FunctionEnvMut<'_, Self>, mut signals: Vec, ) -> Result { let env = ctx.data(); - if let Some(handler) = env.inner().signal.clone() { + let inner = env + .try_inner() + .ok_or_else(|| WasiError::Exit(Errno::Fault.into()))?; + if let Some(handler) = inner.signal.clone() { // We might also have signals that trigger on timers let mut now = 0; let has_signal_interval = { @@ -700,18 +714,23 @@ impl WasiEnv { /// Providers safe access to the initialized part of WasiEnv /// (it must be initialized before it can be used) - pub(crate) fn inner(&self) -> WasiInstanceGuard<'_> { + /// This has been marked as unsafe as it will panic if its executed + /// on the wrong thread or before the inner is set + pub(crate) unsafe fn inner(&self) -> WasiInstanceGuard<'_> { self.inner.get().expect( "You must initialize the WasiEnv before using it and can not pass it between threads", ) } + /// Providers safe access to the initialized part of WasiEnv + pub(crate) fn try_inner(&self) -> Option> { + self.inner.get() + } + /// Providers safe access to the initialized part of WasiEnv /// (it must be initialized before it can be used) - pub(crate) fn inner_mut(&mut self) -> WasiInstanceGuardMut<'_> { - self.inner.get_mut().expect( - "You must initialize the WasiEnv before using it and can not pass it between threads", - ) + pub(crate) fn try_inner_mut(&mut self) -> Option> { + self.inner.get_mut() } /// Sets the inner object (this should only be called when @@ -737,20 +756,37 @@ impl WasiEnv { /// Providers safe access to the memory /// (it must be initialized before it can be used) - pub(crate) fn memory(&self) -> WasiInstanceGuardMemory<'_> { - self.inner().memory() + pub(crate) fn try_memory(&self) -> Option> { + self.try_inner().map(|i| i.memory()) + } + + /// Providers safe access to the memory + /// (it must be initialized before it can be used) + pub(crate) fn try_memory_view<'a>( + &self, + store: &'a (impl AsStoreRef + ?Sized), + ) -> Option> { + self.try_memory().map(|m| m.view(store)) } /// Providers safe access to the memory /// (it must be initialized before it can be used) - pub(crate) fn memory_view<'a>(&self, store: &'a (impl AsStoreRef + ?Sized)) -> MemoryView<'a> { - self.memory().view(store) + /// This has been marked as unsafe as it will panic if its executed + /// on the wrong thread or before the inner is set + pub(crate) unsafe fn memory_view<'a>( + &self, + store: &'a (impl AsStoreRef + ?Sized), + ) -> MemoryView<'a> { + self.try_memory_view(store).expect( + "You must initialize the WasiEnv before using it and can not pass it between threads", + ) } /// Copy the lazy reference so that when it's initialized during the /// export phase, all the other references get a copy of it - pub(crate) fn memory_clone(&self) -> Memory { - self.inner().memory_clone() + #[allow(dead_code)] + pub(crate) fn try_memory_clone(&self) -> Option { + self.try_inner().map(|i| i.memory_clone()) } /// Get the WASI state @@ -782,7 +818,12 @@ impl WasiEnv { self.state.std_dev_get(fd) } - pub(crate) fn get_memory_and_wasi_state<'a>( + /// Unsafe: + /// + /// This will access the memory of the WASM process and create a view into it which is + /// inherently unsafe as it could corrupt the memory. Also accessing the memory is not + /// thread safe. + pub(crate) unsafe fn get_memory_and_wasi_state<'a>( &'a self, store: &'a impl AsStoreRef, _mem_index: u32, @@ -792,7 +833,12 @@ impl WasiEnv { (memory, state) } - pub(crate) fn get_memory_and_wasi_state_and_inodes<'a>( + /// Unsafe: + /// + /// This will access the memory of the WASM process and create a view into it which is + /// inherently unsafe as it could corrupt the memory. Also accessing the memory is not + /// thread safe. + pub(crate) unsafe fn get_memory_and_wasi_state_and_inodes<'a>( &'a self, store: &'a impl AsStoreRef, _mem_index: u32, diff --git a/lib/wasi/src/state/func_env.rs b/lib/wasi/src/state/func_env.rs index cb82f69aff3..4157560d6b2 100644 --- a/lib/wasi/src/state/func_env.rs +++ b/lib/wasi/src/state/func_env.rs @@ -6,13 +6,19 @@ use wasmer_wasix_types::wasi::ExitCode; use crate::{ import_object_for_all_wasi_versions, - os::task::thread::DEFAULT_STACK_SIZE, runtime::SpawnMemoryType, state::WasiInstanceHandles, utils::{get_wasi_version, get_wasi_versions, store::restore_snapshot}, InstanceSnapshot, WasiEnv, WasiError, WasiThreadError, }; +/// The default stack size for WASIX - the number itself is the default that compilers +/// have used in the past when compiling WASM apps. +/// +/// (this is only used for programs that have no stack pointer) +const DEFAULT_STACK_SIZE: u64 = 1_048_576u64; +const DEFAULT_STACK_BASE: u64 = DEFAULT_STACK_SIZE; + #[derive(Clone)] pub struct WasiFunctionEnv { pub env: FunctionEnv, @@ -136,6 +142,7 @@ impl WasiFunctionEnv { )?; let new_inner = WasiInstanceHandles::new(memory, store, instance); + let stack_pointer = new_inner.stack_pointer.clone(); let env = self.data_mut(store); env.set_inner(new_inner); @@ -145,17 +152,19 @@ impl WasiFunctionEnv { // If the stack offset and size is not set then do so if update_layout { // Set the base stack - let mut stack_base = if let Some(stack_pointer) = env.inner().stack_pointer.clone() { + let stack_base = if let Some(stack_pointer) = stack_pointer { match stack_pointer.get(store) { wasmer::Value::I32(a) => a as u64, wasmer::Value::I64(a) => a as u64, - _ => 0, + _ => DEFAULT_STACK_BASE, } } else { - 0 + DEFAULT_STACK_BASE }; if stack_base == 0 { - stack_base = DEFAULT_STACK_SIZE; + return Err(ExportError::Missing( + "stack_pointer is not set to the upper stack range".to_string(), + )); } // Update the stack layout which is need for asyncify @@ -164,6 +173,7 @@ impl WasiFunctionEnv { layout.stack_upper = stack_base; layout.stack_size = layout.stack_upper - layout.stack_lower; } + tracing::trace!("initializing with layout {:?}", self.data(store).layout); Ok(()) } @@ -190,6 +200,11 @@ impl WasiFunctionEnv { Ok(resolver) } + /// # Safety + /// + /// This function should only be called from within a syscall + /// as it can potentially execute local thread variable cleanup + /// code pub fn cleanup(&self, store: &mut impl AsStoreMut, exit_code: Option) { trace!( "wasi[{}:{}]::cleanup - destroying local thread variables", @@ -213,28 +228,26 @@ impl WasiFunctionEnv { to_local_destroy }; if !to_local_destroy.is_empty() { - if let Some(thread_local_destroy) = self - .data(store) - .inner() - .thread_local_destroy - .as_ref() - .cloned() - { - for (user_data, val) in to_local_destroy { - let user_data_low: u32 = (user_data & 0xFFFFFFFF) as u32; - let user_data_high: u32 = (user_data >> 32) as u32; - - let val_low: u32 = (val & 0xFFFFFFFF) as u32; - let val_high: u32 = (val >> 32) as u32; - - let _ = thread_local_destroy.call( - store, - user_data_low as i32, - user_data_high as i32, - val_low as i32, - val_high as i32, - ); + if let Some(inner) = self.data(store).try_inner() { + if let Some(thread_local_destroy) = inner.thread_local_destroy.as_ref().cloned() { + for (user_data, val) in to_local_destroy { + let user_data_low: u32 = (user_data & 0xFFFFFFFF) as u32; + let user_data_high: u32 = (user_data >> 32) as u32; + + let val_low: u32 = (val & 0xFFFFFFFF) as u32; + let val_high: u32 = (val >> 32) as u32; + + let _ = thread_local_destroy.call( + store, + user_data_low as i32, + user_data_high as i32, + val_low as i32, + val_high as i32, + ); + } } + } else { + tracing::warn!("unable to clean up thread local variables as the inner instance is not accessible"); } } diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs index 7afa0e52531..3a5b93d9a45 100644 --- a/lib/wasi/src/syscalls/legacy/snapshot0.rs +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -23,7 +23,7 @@ pub fn fd_filestat_get( buf: WasmPtr, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let result = syscalls::fd_filestat_get_old::(ctx.as_mut(), fd, buf); result @@ -40,7 +40,7 @@ pub fn path_filestat_get( buf: WasmPtr, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let result = syscalls::path_filestat_get_old::(ctx.as_mut(), fd, flags, path, path_len, buf); @@ -77,12 +77,9 @@ pub fn poll_oneoff( nevents: WasmPtr, ) -> Result { wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); - if handle_rewind::(&mut ctx) { - return Ok(Errno::Success); - } let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let mut subscriptions = Vec::new(); let in_origs = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions)); let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); @@ -94,17 +91,15 @@ pub fn poll_oneoff( )); } - // We clear the number of events - wasi_try_mem_ok!(nevents.write(&memory, 0)); - // Function to invoke once the poll is finished - let process_events = move |memory: &'_ Memory, store: &'_ dyn AsStoreRef, triggered_events| { + let process_events = |ctx: &FunctionEnvMut<'_, WasiEnv>, triggered_events: Vec| { + let env = ctx.data(); + let memory = unsafe { env.memory_view(&ctx) }; + // Process all the events that were triggered - let mut view = memory.view(store); let mut events_seen: u32 = 0; - let event_array = wasi_try_mem!(out_.slice(&view, nsubscriptions)); + let event_array = wasi_try_mem!(out_.slice(&memory, nsubscriptions)); for event in triggered_events { - let event: Event = event; let event = Snapshot0Event { userdata: event.userdata, error: event.error, @@ -121,11 +116,14 @@ pub fn poll_oneoff( wasi_try_mem!(event_array.index(events_seen as u64).write(event)); events_seen += 1; } - let out_ptr = nevents.deref(&view); + let out_ptr = nevents.deref(&memory); wasi_try_mem!(out_ptr.write(events_seen)); Errno::Success }; + // We clear the number of events + wasi_try_mem_ok!(nevents.write(&memory, 0)); + // Poll and receive all the events that triggered syscalls::poll_oneoff_internal::(ctx, subscriptions, process_events) } diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 70d6877c99d..b6bd4d2b899 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -47,7 +47,7 @@ pub(crate) use std::{ thread::LocalKey, time::Duration, }; -use std::{io::IoSlice, mem::MaybeUninit, time::Instant}; +use std::{io::IoSlice, marker::PhantomData, mem::MaybeUninit, time::Instant}; pub(crate) use bytes::{Bytes, BytesMut}; pub(crate) use cooked_waker::IntoWaker; @@ -114,6 +114,7 @@ use crate::{ fs_error_into_wasi_err, virtual_file_type_to_wasi_file_type, Fd, InodeVal, Kind, MAX_SYMLINKS, }, + os::task::thread::RewindResult, utils::store::InstanceSnapshot, DeepSleepWork, RewindPostProcess, RewindState, VirtualBusError, WasiInodes, }; @@ -217,7 +218,10 @@ pub(crate) fn read_bytes( // TODO: remove allow once inodes are refactored (see comments on [`WasiState`]) #[allow(clippy::await_holding_lock)] -pub async fn stderr_write(ctx: &FunctionEnvMut<'_, WasiEnv>, buf: &[u8]) -> Result<(), Errno> { +pub async unsafe fn stderr_write( + ctx: &FunctionEnvMut<'_, WasiEnv>, + buf: &[u8], +) -> Result<(), Errno> { let env = ctx.data(); let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(ctx, 0); @@ -333,21 +337,26 @@ where } /// Future that will be polled by asyncify methods -pub type AsyncifyFuture = dyn Future> + Send + Sync + 'static; +/// (the return value is what will be returned in rewind +/// or in the instant response) +pub type AsyncifyFuture = dyn Future + Send + Sync + 'static; // This poller will process any signals when the main working function is idle -struct AsyncifyPoller<'a, 'b, 'c> { - signal_set: bool, +struct AsyncifyPoller<'a, T, Fut> +where + Fut: Future + Send + Sync + 'static, +{ + process_signals: bool, thread: WasiThread, - memory: WasiInstanceGuardMemory<'a>, - store: &'b dyn AsStoreRef, - work: &'c mut Pin>, + work: &'a mut Pin>, } -impl<'a, 'b, 'c> Future for AsyncifyPoller<'a, 'b, 'c> { - type Output = Result, WasiError>; +impl<'a, T, Fut> Future for AsyncifyPoller<'a, T, Fut> +where + Fut: Future + Send + Sync + 'static, +{ + type Output = Result; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let store = self.store; - let memory = self.memory.clone(); if let Poll::Ready(res) = self.work.as_mut().poll(cx) { return Poll::Ready(Ok(res)); } @@ -357,7 +366,7 @@ impl<'a, 'b, 'c> Future for AsyncifyPoller<'a, 'b, 'c> { Errno::Child.into() })))); } - if !self.signal_set && self.thread.has_signals_or_subscribe(cx.waker()) { + if self.process_signals && self.thread.has_signals_or_subscribe(cx.waker()) { let signals = self.thread.signals().lock().unwrap(); for sig in signals.0.iter() { if *sig == Signal::Sigint @@ -369,16 +378,15 @@ impl<'a, 'b, 'c> Future for AsyncifyPoller<'a, 'b, 'c> { return Poll::Ready(Err(WasiError::Exit(exit_code))); } } - return Poll::Ready(Ok(Err(Errno::Intr))); } Poll::Pending } } -pub enum AsyncifyAction<'a> { +pub enum AsyncifyAction<'a, R> { /// Indicates that asyncify callback finished and the /// caller now has ownership of the ctx again - Finish(FunctionEnvMut<'a, WasiEnv>), + Finish(FunctionEnvMut<'a, WasiEnv>, R), /// Indicates that asyncify should unwind by immediately exiting /// the current function Unwind, @@ -393,44 +401,24 @@ pub enum AsyncifyAction<'a> { /// or it will return an WasiError which will exit the WASM call using asyncify /// and instead process it on a shared task /// -pub(crate) fn __asyncify_with_deep_sleep( +pub(crate) fn __asyncify_with_deep_sleep( ctx: FunctionEnvMut<'_, WasiEnv>, - timeout: Option, deep_sleep_time: Duration, - work: Pin>, - mut after: After, -) -> Result, WasiError> + trigger: Fut, +) -> Result, WasiError> where - After: RewindPostProcess + Send + Sync + 'static, + T: serde::Serialize + serde::de::DeserializeOwned, + Fut: Future + Send + Sync + 'static, { - // We build a wrapper around the polling struct that will - // check for a timeout - struct WorkWithTimeout { - inner: Pin>, - timeout: Option + Send + Sync>>>, - } - impl Future for WorkWithTimeout { - type Output = Result<(), Errno>; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let inner = self.inner.as_mut(); - if let Poll::Ready(res) = inner.poll(cx) { - return Poll::Ready(res); - } - if let Some(timeout) = self.timeout.as_mut() { - if timeout.as_mut().poll(cx).is_ready() { - self.timeout.take(); - return Poll::Ready(Err(Errno::Timedout)); - } - } + // Determine if we should process signals or now + let process_signals = ctx + .data() + .try_inner() + .map(|i| !i.signal_set) + .unwrap_or(true); - Poll::Pending - } - } - let work = Box::pin(WorkWithTimeout { - inner: work, - timeout: timeout.map(|timeout| ctx.data().tasks().sleep_now(timeout)), - }); - let mut work: Pin> = work; + // Box up the trigger + let mut trigger = Box::pin(trigger); // Define the work let tasks = ctx.data().tasks().clone(); @@ -449,21 +437,22 @@ where Ok(tokio::select! { // Inner wait with finializer res = AsyncifyPoller { - signal_set: ctx.data().inner().signal_set, + process_signals, thread: ctx.data().thread.clone(), - memory: ctx.data().memory(), - store: &ctx, - work: &mut work, + work: &mut trigger, } => { - after.finish(ctx.data(), &ctx, res?); - AsyncifyAction::Finish(ctx) + let result = res?; + AsyncifyAction::Finish(ctx, result) }, // Determines when and if we should go into a deep sleep _ = deep_sleep_wait => { let pid = ctx.data().pid(); let tid = ctx.data().tid(); tracing::trace!(%pid, %tid, "thread entering deep sleep"); - deep_sleep::(ctx, work, after)?; + deep_sleep::(ctx, Box::pin(async move { + let result = trigger.await; + bincode::serialize(&result).unwrap().into() + }))?; AsyncifyAction::Unwind }, }) @@ -473,95 +462,6 @@ where tasks.block_on(work) } -pub(crate) type AsyncifyWorkAfter = dyn FnOnce(&Memory, &dyn AsStoreRef, Result) -> Result<(), ExitCode> - + Send - + Sync - + 'static; - -/// Asyncify takes the current thread and blocks on the async runtime associated with it -/// thus allowed for asynchronous operations to execute. It has built in functionality -/// to (optionally) timeout the IO, force exit the process, callback signals and pump -/// synchronous IO engine -/// -/// This will either return the `ctx` as the asyncify has completed successfully -/// or it will return an WasiError which will exit the WASM call using asyncify -/// and instead process it on a shared task -/// -pub(crate) fn __asyncify_with_deep_sleep_ext( - ctx: FunctionEnvMut<'_, WasiEnv>, - timeout: Option, - deep_sleep_time: Duration, - trigger: Fut, - after: After, -) -> Result, WasiError> -where - T: Send + Sync + 'static, - Fut: Future + Send + Sync + 'static, - After: FnOnce(&Memory, &dyn AsStoreRef, Result) -> Result<(), ExitCode> - + Send - + Sync - + 'static, -{ - let ret = Arc::new(Mutex::new(None)); - struct Poller { - work: Pin + Send + Sync + 'static>>, - ret: Arc>>, - } - impl Future for Poller { - type Output = Result<(), Errno>; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.work.as_mut().poll(cx) { - Poll::Ready(ret) => { - let mut guard = self.ret.lock().unwrap(); - guard.replace(ret); - Poll::Ready(Ok(())) - } - Poll::Pending => Poll::Pending, - } - } - } - struct Finisher { - after: Option>>, - ret: Arc>>, - } - impl RewindPostProcess for Finisher { - fn finish( - &mut self, - env: &WasiEnv, - store: &dyn AsStoreRef, - res: Result<(), Errno>, - ) -> Result<(), ExitCode> { - if let Some(after) = self.after.take() { - let res = match res { - Ok(()) => { - let mut guard = self.ret.lock().unwrap(); - guard.take().ok_or(Errno::Unknown) - } - Err(err) => Err(err), - }; - let memory = env.memory(); - after(memory.deref(), store, res) - } else { - Err(ExitCode::Errno(Errno::Unknown)) - } - } - } - - __asyncify_with_deep_sleep::( - ctx, - timeout, - deep_sleep_time, - Box::pin(Poller:: { - work: Box::pin(trigger), - ret: ret.clone(), - }), - Finisher { - after: Some(Box::new(after)), - ret, - }, - ) -} - /// Asyncify takes the current thread and blocks on the async runtime associated with it /// thus allowed for asynchronous operations to execute. It has built in functionality /// to (optionally) timeout the IO, force exit the process, callback signals and pump @@ -894,7 +794,7 @@ pub(crate) fn get_stack_upper(env: &WasiEnv) -> u64 { env.layout.stack_upper } -pub(crate) fn get_memory_stack_pointer( +pub(crate) unsafe fn get_memory_stack_pointer( ctx: &mut FunctionEnvMut<'_, WasiEnv>, ) -> Result { // Get the current value of the stack pointer (which we will use @@ -912,7 +812,7 @@ pub(crate) fn get_memory_stack_pointer( Ok(stack_pointer) } -pub(crate) fn get_memory_stack_offset( +pub(crate) unsafe fn get_memory_stack_offset( ctx: &mut FunctionEnvMut<'_, WasiEnv>, ) -> Result { let stack_upper = get_stack_upper(ctx.data()); @@ -928,7 +828,12 @@ pub(crate) fn set_memory_stack_offset( // Sets the stack pointer let stack_upper = get_stack_upper(env); let stack_pointer = stack_upper - offset; - if let Some(stack_pointer_ptr) = env.inner().stack_pointer.clone() { + if let Some(stack_pointer_ptr) = env + .try_inner() + .ok_or_else(|| "unable to access the stack pointer of the instance".to_string())? + .stack_pointer + .clone() + { match stack_pointer_ptr.get(store) { Value::I32(_) => { stack_pointer_ptr.set(store, Value::I32(stack_pointer as i32)); @@ -957,7 +862,12 @@ pub(crate) fn get_memory_stack( // Get the current value of the stack pointer (which we will use // to save all of the stack) let stack_base = get_stack_upper(env); - let stack_pointer = if let Some(stack_pointer) = env.inner().stack_pointer.clone() { + let stack_pointer = if let Some(stack_pointer) = env + .try_inner() + .ok_or_else(|| "unable to access the stack pointer of the instance".to_string())? + .stack_pointer + .clone() + { match stack_pointer.get(store) { Value::I32(a) => a as u64, Value::I64(a) => a as u64, @@ -966,7 +876,9 @@ pub(crate) fn get_memory_stack( } else { return Err("failed to save stack: not exported __stack_pointer global".to_string()); }; - let memory = env.memory_view(store); + let memory = env + .try_memory_view(store) + .ok_or_else(|| "unable to access the memory of the instance".to_string())?; let stack_offset = env.layout.stack_upper - stack_pointer; // Read the memory stack into a vector @@ -1003,7 +915,9 @@ pub(crate) fn set_memory_stack( .map_err(|_| "failed to restore stack: stack pointer overflow".to_string())?, ); - let memory = env.memory_view(store); + let memory = env + .try_memory_view(store) + .ok_or_else(|| "unable to set the stack pointer of the instance".to_string())?; stack_ptr .slice( &memory, @@ -1022,14 +936,10 @@ pub(crate) fn set_memory_stack( /// Puts the process to deep sleep and wakes it again when /// the supplied future completes #[must_use = "you must return the result immediately so the stack can unwind"] -pub(crate) fn deep_sleep( +pub(crate) fn deep_sleep( mut ctx: FunctionEnvMut<'_, WasiEnv>, trigger: Pin>, - after: After, -) -> Result<(), WasiError> -where - After: RewindPostProcess + Send + Sync + 'static, -{ +) -> Result<(), WasiError> { // Grab all the globals and serialize them let store_data = crate::utils::store::capture_snapshot(&mut ctx.as_store_mut()) .serialize() @@ -1048,7 +958,6 @@ where rewind_stack: rewind_stack.freeze(), store_data, is_64bit: M::is_64bit(), - finish: Box::new(after), }, }), )))) @@ -1085,7 +994,7 @@ where // Perform a check to see if we have enough room let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; // Write the addresses to the start of the stack space let unwind_pointer = env.layout.stack_lower; @@ -1108,7 +1017,10 @@ where // Invoke the callback that will prepare to unwind // We need to start unwinding the stack let asyncify_data = wasi_try_ok!(unwind_pointer.try_into().map_err(|_| Errno::Overflow)); - if let Some(asyncify_start_unwind) = env.inner().asyncify_start_unwind.clone() { + if let Some(asyncify_start_unwind) = wasi_try_ok!(env.try_inner().ok_or(Errno::Fault)) + .asyncify_start_unwind + .clone() + { asyncify_start_unwind.call(&mut ctx, asyncify_data); } else { warn!("failed to unwind the stack because the asyncify_start_rewind export is missing"); @@ -1132,7 +1044,9 @@ where ctx.as_store_mut().on_called(move |mut store| { let mut ctx = func.into_mut(&mut store); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = env + .try_memory_view(&ctx) + .ok_or_else(|| "failed to save stack: stack pointer overflow - unable to access the memory of the instance".to_string())?; let unwind_data_ptr: WasmPtr<__wasi_asyncify_t, M> = WasmPtr::new( unwind_pointer @@ -1168,7 +1082,12 @@ where .map_err(|err| format!("failed to read stack: {}", err))?; // Notify asyncify that we are no longer unwinding - if let Some(asyncify_stop_unwind) = env.inner().asyncify_stop_unwind.clone() { + if let Some(asyncify_stop_unwind) = env + .try_inner() + .into_iter() + .filter_map(|i| i.asyncify_stop_unwind.clone()) + .next() + { asyncify_stop_unwind.call(&mut ctx); } else { warn!("failed to unwind the stack because the asyncify_start_rewind export is missing"); @@ -1184,14 +1103,34 @@ where #[instrument(level = "debug", skip_all, fields(memory_stack_len = memory_stack.len(), rewind_stack_len = rewind_stack.len(), store_data_len = store_data.len()))] #[must_use = "the action must be passed to the call loop"] -pub fn rewind( +pub fn rewind( + ctx: FunctionEnvMut, + memory_stack: Bytes, + rewind_stack: Bytes, + store_data: Bytes, + result: T, +) -> Errno +where + T: serde::Serialize, +{ + let rewind_result = bincode::serialize(&result).unwrap().into(); + rewind_ext::(ctx, memory_stack, rewind_stack, store_data, rewind_result) +} + +#[instrument(level = "debug", skip_all, fields(memory_stack_len = memory_stack.len(), rewind_stack_len = rewind_stack.len(), store_data_len = store_data.len()))] +#[must_use = "the action must be passed to the call loop"] +pub fn rewind_ext( mut ctx: FunctionEnvMut, memory_stack: Bytes, rewind_stack: Bytes, store_data: Bytes, + rewind_result: Bytes, ) -> Errno { // Store the memory stack so that it can be restored later - super::REWIND.with(|cell| cell.replace(Some(memory_stack))); + ctx.data_mut().thread.set_rewind(RewindResult { + memory_stack, + rewind_result, + }); // Deserialize the store data back into a snapshot let store_snapshot = match InstanceSnapshot::deserialize(&store_data[..]) { @@ -1203,7 +1142,13 @@ pub fn rewind( }; crate::utils::store::restore_snapshot(&mut ctx, &store_snapshot); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = match env.try_memory_view(&ctx) { + Some(v) => v, + None => { + warn!("snapshot restore failed - unable to access the memory of the instance"); + return Errno::Unknown; + } + }; // Write the addresses to the start of the stack space let rewind_pointer = env.layout.stack_lower; @@ -1244,31 +1189,49 @@ pub fn rewind( // Invoke the callback that will prepare to rewind let asyncify_data = wasi_try!(rewind_pointer.try_into().map_err(|_| Errno::Overflow)); - if let Some(asyncify_start_rewind) = env.inner().asyncify_start_rewind.clone() { + if let Some(asyncify_start_rewind) = env + .try_inner() + .into_iter() + .filter_map(|a| a.asyncify_start_rewind.clone()) + .next() + { asyncify_start_rewind.call(&mut ctx, asyncify_data); } else { - warn!("failed to rewind the stack because the asyncify_start_rewind export is missing"); + warn!("failed to rewind the stack because the asyncify_start_rewind export is missing or inaccessible"); return Errno::Noexec; } Errno::Success } -pub(crate) fn handle_rewind(ctx: &mut FunctionEnvMut<'_, WasiEnv>) -> bool { +pub(crate) unsafe fn handle_rewind( + ctx: &mut FunctionEnvMut<'_, WasiEnv>, +) -> Option +where + T: serde::de::DeserializeOwned, +{ // If the stack has been restored - if let Some(memory_stack) = super::REWIND.with(|cell| cell.borrow_mut().take()) { + if let Some(result) = ctx.data_mut().thread.take_rewind() { + // Deserialize the result + let memory_stack = result.memory_stack; + let ret = bincode::deserialize(&result.rewind_result) + .expect("failed to deserialize the rewind result"); + // Notify asyncify that we are no longer rewinding let env = ctx.data(); - if let Some(asyncify_stop_rewind) = env.inner().asyncify_stop_rewind.clone() { + if let Some(asyncify_stop_rewind) = env.inner().asyncify_stop_unwind.clone() { asyncify_stop_rewind.call(ctx); + } else { + warn!("failed to handle rewind because the asyncify_start_rewind export is missing or inaccessible"); + return None; } // Restore the memory stack let (env, mut store) = ctx.data_and_store_mut(); set_memory_stack::(env, &mut store, memory_stack); - true + Some(ret) } else { - false + None } } diff --git a/lib/wasi/src/syscalls/wasi/args_get.rs b/lib/wasi/src/syscalls/wasi/args_get.rs index ec29be238a4..8a316d92bbe 100644 --- a/lib/wasi/src/syscalls/wasi/args_get.rs +++ b/lib/wasi/src/syscalls/wasi/args_get.rs @@ -17,7 +17,7 @@ pub fn args_get( argv_buf: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let args = state .args diff --git a/lib/wasi/src/syscalls/wasi/args_sizes_get.rs b/lib/wasi/src/syscalls/wasi/args_sizes_get.rs index 4e60962fc56..08ec71c1679 100644 --- a/lib/wasi/src/syscalls/wasi/args_sizes_get.rs +++ b/lib/wasi/src/syscalls/wasi/args_sizes_get.rs @@ -15,7 +15,7 @@ pub fn args_sizes_get( argv_buf_size: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let argc = argc.deref(&memory); let argv_buf_size = argv_buf_size.deref(&memory); diff --git a/lib/wasi/src/syscalls/wasi/clock_res_get.rs b/lib/wasi/src/syscalls/wasi/clock_res_get.rs index 4c24a9916b6..ddcac9e9dbc 100644 --- a/lib/wasi/src/syscalls/wasi/clock_res_get.rs +++ b/lib/wasi/src/syscalls/wasi/clock_res_get.rs @@ -16,7 +16,7 @@ pub fn clock_res_get( resolution: WasmPtr, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let out_addr = resolution.deref(&memory); let t_out = wasi_try!(platform_clock_res_get(clock_id, out_addr)); diff --git a/lib/wasi/src/syscalls/wasi/clock_time_get.rs b/lib/wasi/src/syscalls/wasi/clock_time_get.rs index c7f530f02ce..45c0e7683fb 100644 --- a/lib/wasi/src/syscalls/wasi/clock_time_get.rs +++ b/lib/wasi/src/syscalls/wasi/clock_time_get.rs @@ -19,7 +19,7 @@ pub fn clock_time_get( time: WasmPtr, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let mut t_out = wasi_try!(platform_clock_time_get(clock_id, precision)); { diff --git a/lib/wasi/src/syscalls/wasi/clock_time_set.rs b/lib/wasi/src/syscalls/wasi/clock_time_set.rs index be78283306c..5f9cff89eba 100644 --- a/lib/wasi/src/syscalls/wasi/clock_time_set.rs +++ b/lib/wasi/src/syscalls/wasi/clock_time_set.rs @@ -15,7 +15,7 @@ pub fn clock_time_set( time: Timestamp, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let precision = 1 as Timestamp; let t_now = wasi_try!(platform_clock_time_get(clock_id, precision)); diff --git a/lib/wasi/src/syscalls/wasi/environ_get.rs b/lib/wasi/src/syscalls/wasi/environ_get.rs index 35425551c5d..fabd186be92 100644 --- a/lib/wasi/src/syscalls/wasi/environ_get.rs +++ b/lib/wasi/src/syscalls/wasi/environ_get.rs @@ -16,7 +16,7 @@ pub fn environ_get( environ_buf: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; write_buffer_array(&memory, &state.envs, environ, environ_buf) } diff --git a/lib/wasi/src/syscalls/wasi/environ_sizes_get.rs b/lib/wasi/src/syscalls/wasi/environ_sizes_get.rs index 7c9496f5cc0..eb3b3f08d98 100644 --- a/lib/wasi/src/syscalls/wasi/environ_sizes_get.rs +++ b/lib/wasi/src/syscalls/wasi/environ_sizes_get.rs @@ -15,7 +15,7 @@ pub fn environ_sizes_get( environ_buf_size: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let environ_count = environ_count.deref(&memory); let environ_buf_size = environ_buf_size.deref(&memory); diff --git a/lib/wasi/src/syscalls/wasi/fd_allocate.rs b/lib/wasi/src/syscalls/wasi/fd_allocate.rs index 9d5bcdb8579..34b45c6ae99 100644 --- a/lib/wasi/src/syscalls/wasi/fd_allocate.rs +++ b/lib/wasi/src/syscalls/wasi/fd_allocate.rs @@ -18,7 +18,7 @@ pub fn fd_allocate( len: Filesize, ) -> Errno { let env = ctx.data(); - let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; diff --git a/lib/wasi/src/syscalls/wasi/fd_close.rs b/lib/wasi/src/syscalls/wasi/fd_close.rs index febc4c81e58..31a2a97581b 100644 --- a/lib/wasi/src/syscalls/wasi/fd_close.rs +++ b/lib/wasi/src/syscalls/wasi/fd_close.rs @@ -15,7 +15,7 @@ use crate::syscalls::*; #[instrument(level = "debug", skip_all, fields(pid = ctx.data().process.pid().raw(), %fd), ret, err)] pub fn fd_close(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result { let env = ctx.data(); - let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; wasi_try_ok!(state.fs.close_fd(fd)); Ok(Errno::Success) diff --git a/lib/wasi/src/syscalls/wasi/fd_dup.rs b/lib/wasi/src/syscalls/wasi/fd_dup.rs index 79be5cc7870..a25fb3750bb 100644 --- a/lib/wasi/src/syscalls/wasi/fd_dup.rs +++ b/lib/wasi/src/syscalls/wasi/fd_dup.rs @@ -16,7 +16,7 @@ pub fn fd_dup( ret_fd: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let fd = wasi_try!(state.fs.clone_fd(fd)); Span::current().record("ret_fd", fd); diff --git a/lib/wasi/src/syscalls/wasi/fd_event.rs b/lib/wasi/src/syscalls/wasi/fd_event.rs index 52d6c22a0ce..d1f7272abd9 100644 --- a/lib/wasi/src/syscalls/wasi/fd_event.rs +++ b/lib/wasi/src/syscalls/wasi/fd_event.rs @@ -11,7 +11,7 @@ pub fn fd_event( ret_fd: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, state, mut inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let is_semaphore = flags & EVENT_FD_FLAGS_SEMAPHORE != 0; let kind = diff --git a/lib/wasi/src/syscalls/wasi/fd_fdstat_get.rs b/lib/wasi/src/syscalls/wasi/fd_fdstat_get.rs index 229c11ca16a..4f0ced4a3b1 100644 --- a/lib/wasi/src/syscalls/wasi/fd_fdstat_get.rs +++ b/lib/wasi/src/syscalls/wasi/fd_fdstat_get.rs @@ -16,7 +16,7 @@ pub fn fd_fdstat_get( buf_ptr: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let stat = wasi_try!(state.fs.fdstat(fd)); let buf = buf_ptr.deref(&memory); diff --git a/lib/wasi/src/syscalls/wasi/fd_fdstat_set_flags.rs b/lib/wasi/src/syscalls/wasi/fd_fdstat_set_flags.rs index 64269bb70ee..67c055a500d 100644 --- a/lib/wasi/src/syscalls/wasi/fd_fdstat_set_flags.rs +++ b/lib/wasi/src/syscalls/wasi/fd_fdstat_set_flags.rs @@ -16,7 +16,7 @@ pub fn fd_fdstat_set_flags( ) -> Result { { let env = ctx.data(); - let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (_, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf)); let inode = fd_entry.inode.clone(); @@ -27,7 +27,7 @@ pub fn fd_fdstat_set_flags( } let env = ctx.data(); - let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (_, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf)); fd_entry.flags = flags; diff --git a/lib/wasi/src/syscalls/wasi/fd_fdstat_set_rights.rs b/lib/wasi/src/syscalls/wasi/fd_fdstat_set_rights.rs index d3d87fb0b30..ec724f9d536 100644 --- a/lib/wasi/src/syscalls/wasi/fd_fdstat_set_rights.rs +++ b/lib/wasi/src/syscalls/wasi/fd_fdstat_set_rights.rs @@ -18,7 +18,7 @@ pub fn fd_fdstat_set_rights( fs_rights_inheriting: Rights, ) -> Errno { let env = ctx.data(); - let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try!(fd_map.get_mut(&fd).ok_or(Errno::Badf)); diff --git a/lib/wasi/src/syscalls/wasi/fd_filestat_get.rs b/lib/wasi/src/syscalls/wasi/fd_filestat_get.rs index 910915be9e3..46a3dc33e05 100644 --- a/lib/wasi/src/syscalls/wasi/fd_filestat_get.rs +++ b/lib/wasi/src/syscalls/wasi/fd_filestat_get.rs @@ -19,7 +19,7 @@ pub fn fd_filestat_get( let stat = wasi_try!(fd_filestat_get_internal(&mut ctx, fd)); let env = ctx.data(); - let (memory, _) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, _) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let buf = buf.deref(&memory); wasi_try_mem!(buf.write(stat)); @@ -39,7 +39,7 @@ pub(crate) fn fd_filestat_get_internal( fd: WasiFd, ) -> Result { let env = ctx.data(); - let (_, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (_, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let fd_entry = state.fs.get_fd(fd)?; if !fd_entry.rights.contains(Rights::FD_FILESTAT_GET) { return Err(Errno::Access); @@ -65,7 +65,7 @@ pub fn fd_filestat_get_old( let stat = wasi_try!(fd_filestat_get_internal(&mut ctx, fd)); let env = ctx.data(); - let (memory, _) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, _) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let old_stat = Snapshot0Filestat { st_dev: stat.st_dev, st_ino: stat.st_ino, diff --git a/lib/wasi/src/syscalls/wasi/fd_filestat_set_size.rs b/lib/wasi/src/syscalls/wasi/fd_filestat_set_size.rs index 05ff6bb7f02..b62e9086740 100644 --- a/lib/wasi/src/syscalls/wasi/fd_filestat_set_size.rs +++ b/lib/wasi/src/syscalls/wasi/fd_filestat_set_size.rs @@ -15,7 +15,7 @@ pub fn fd_filestat_set_size( st_size: Filesize, ) -> Errno { let env = ctx.data(); - let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; diff --git a/lib/wasi/src/syscalls/wasi/fd_filestat_set_times.rs b/lib/wasi/src/syscalls/wasi/fd_filestat_set_times.rs index 3f9c987c530..5eea1e19ad6 100644 --- a/lib/wasi/src/syscalls/wasi/fd_filestat_set_times.rs +++ b/lib/wasi/src/syscalls/wasi/fd_filestat_set_times.rs @@ -19,7 +19,7 @@ pub fn fd_filestat_set_times( fst_flags: Fstflags, ) -> Errno { let env = ctx.data(); - let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !fd_entry.rights.contains(Rights::FD_FILESTAT_SET_TIMES) { diff --git a/lib/wasi/src/syscalls/wasi/fd_prestat_dir_name.rs b/lib/wasi/src/syscalls/wasi/fd_prestat_dir_name.rs index 77305bd509b..43984909ab6 100644 --- a/lib/wasi/src/syscalls/wasi/fd_prestat_dir_name.rs +++ b/lib/wasi/src/syscalls/wasi/fd_prestat_dir_name.rs @@ -9,7 +9,7 @@ pub fn fd_prestat_dir_name( path_len: M::Offset, ) -> Errno { let env = ctx.data(); - let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let path_chars = wasi_try_mem!(path.slice(&memory, path_len)); let inode = wasi_try!(state.fs.get_fd_inode(fd)); diff --git a/lib/wasi/src/syscalls/wasi/fd_prestat_get.rs b/lib/wasi/src/syscalls/wasi/fd_prestat_get.rs index 73023338fdd..77a07b91a97 100644 --- a/lib/wasi/src/syscalls/wasi/fd_prestat_get.rs +++ b/lib/wasi/src/syscalls/wasi/fd_prestat_get.rs @@ -16,7 +16,7 @@ pub fn fd_prestat_get( buf: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let prestat_ptr = buf.deref(&memory); wasi_try_mem!(prestat_ptr.write(wasi_try!(state.fs.prestat_fd(fd)))); diff --git a/lib/wasi/src/syscalls/wasi/fd_read.rs b/lib/wasi/src/syscalls/wasi/fd_read.rs index 343eb5f476e..a919315174b 100644 --- a/lib/wasi/src/syscalls/wasi/fd_read.rs +++ b/lib/wasi/src/syscalls/wasi/fd_read.rs @@ -53,10 +53,10 @@ pub fn fd_read( let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow)); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let nread_ref = nread.deref(&memory); wasi_try_mem_ok!(nread_ref.write(bytes_read)); @@ -105,10 +105,10 @@ pub fn fd_pread( let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow)); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let nread_ref = nread.deref(&memory); wasi_try_mem_ok!(nread_ref.write(bytes_read)); @@ -127,7 +127,7 @@ fn fd_read_internal( wasi_try_ok_ok!(WasiEnv::process_signals_and_exit(ctx)?); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let state = env.state(); let fd_entry = wasi_try_ok_ok!(state.fs.get_fd(fd)); @@ -341,7 +341,7 @@ fn fd_read_internal( a => a, })); - let mut memory = env.memory_view(ctx); + let mut memory = unsafe { env.memory_view(ctx) }; let reader = val.to_ne_bytes(); let iovs_arr = wasi_try_mem_ok_ok!(iovs.slice(&memory, iovs_len)); let ret = wasi_try_ok_ok!(read_bytes(&reader[..], &memory, iovs_arr)); @@ -349,7 +349,7 @@ fn fd_read_internal( } Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"), Kind::Buffer { buffer } => { - let memory = env.memory_view(ctx); + let memory = unsafe { env.memory_view(ctx) }; let iovs_arr = wasi_try_mem_ok_ok!(iovs.slice(&memory, iovs_len)); let read = wasi_try_ok_ok!(read_bytes(&buffer[offset..], &memory, iovs_arr)); (read, true) diff --git a/lib/wasi/src/syscalls/wasi/fd_readdir.rs b/lib/wasi/src/syscalls/wasi/fd_readdir.rs index 9004574c80b..0b4359fdef3 100644 --- a/lib/wasi/src/syscalls/wasi/fd_readdir.rs +++ b/lib/wasi/src/syscalls/wasi/fd_readdir.rs @@ -26,7 +26,7 @@ pub fn fd_readdir( bufused: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; // TODO: figure out how this is supposed to work; // is it supposed to pack the buffer full every time until it can't? or do one at a time? diff --git a/lib/wasi/src/syscalls/wasi/fd_renumber.rs b/lib/wasi/src/syscalls/wasi/fd_renumber.rs index 5c4a097af2d..1305003f344 100644 --- a/lib/wasi/src/syscalls/wasi/fd_renumber.rs +++ b/lib/wasi/src/syscalls/wasi/fd_renumber.rs @@ -14,7 +14,7 @@ pub fn fd_renumber(ctx: FunctionEnvMut<'_, WasiEnv>, from: WasiFd, to: WasiFd) - return Errno::Success; } let env = ctx.data(); - let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try!(fd_map.get_mut(&from).ok_or(Errno::Badf)); diff --git a/lib/wasi/src/syscalls/wasi/fd_seek.rs b/lib/wasi/src/syscalls/wasi/fd_seek.rs index 6997146a08a..de4e587eb26 100644 --- a/lib/wasi/src/syscalls/wasi/fd_seek.rs +++ b/lib/wasi/src/syscalls/wasi/fd_seek.rs @@ -25,7 +25,7 @@ pub fn fd_seek( let env = ctx.data(); let state = env.state.clone(); - let (memory, _) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, _) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); if !fd_entry.rights.contains(Rights::FD_SEEK) { @@ -109,7 +109,7 @@ pub fn fd_seek( }; // reborrow let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let new_offset_ref = newoffset.deref(&memory); let fd_entry = wasi_try_ok!(env.state.fs.get_fd(fd)); wasi_try_mem_ok!(new_offset_ref.write(new_offset)); diff --git a/lib/wasi/src/syscalls/wasi/fd_sync.rs b/lib/wasi/src/syscalls/wasi/fd_sync.rs index 8d160b27080..cd18224a273 100644 --- a/lib/wasi/src/syscalls/wasi/fd_sync.rs +++ b/lib/wasi/src/syscalls/wasi/fd_sync.rs @@ -13,7 +13,7 @@ use crate::syscalls::*; #[instrument(level = "debug", skip_all, fields(%fd), ret)] pub fn fd_sync(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result { let env = ctx.data(); - let (_, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); if !fd_entry.rights.contains(Rights::FD_SYNC) { return Ok(Errno::Access); @@ -46,7 +46,7 @@ pub fn fd_sync(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result( offset: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let offset_ref = offset.deref(&memory); let fd_entry = wasi_try!(state.fs.get_fd(fd)); diff --git a/lib/wasi/src/syscalls/wasi/fd_write.rs b/lib/wasi/src/syscalls/wasi/fd_write.rs index 15fb7a0a2cd..fac9b18767a 100644 --- a/lib/wasi/src/syscalls/wasi/fd_write.rs +++ b/lib/wasi/src/syscalls/wasi/fd_write.rs @@ -88,7 +88,7 @@ fn fd_write_internal( let mut env = ctx.data(); let state = env.state.clone(); - let mut memory = env.memory_view(&ctx); + let mut memory = unsafe { env.memory_view(&ctx) }; let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len)); let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); @@ -104,7 +104,7 @@ fn fd_write_internal( let (bytes_written, can_update_cursor) = { let iovs_arr = wasi_try_mem_ok!(iovs_arr.access()); - let (mut memory, _) = env.get_memory_and_wasi_state(&ctx, 0); + let (mut memory, _) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let mut guard = fd_entry.inode.write(); match guard.deref_mut() { Kind::File { handle, .. } => { @@ -251,7 +251,7 @@ fn fd_write_internal( } }; env = ctx.data(); - memory = env.memory_view(&ctx); + memory = unsafe { env.memory_view(&ctx) }; // reborrow and update the size if !is_stdio { @@ -265,7 +265,8 @@ fn fd_write_internal( // we set the size but we don't return any errors if it fails as // pipes and sockets will not do anything with this - let (mut memory, _, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (mut memory, _, inodes) = + unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; // Cast is valid because we don't support 128 bit systems... fd_entry.inode.stat.write().unwrap().st_size += bytes_written as u64; } @@ -273,7 +274,7 @@ fn fd_write_internal( }; Span::current().record("nwritten", bytes_written); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let nwritten_ref = nwritten.deref(&memory); let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow)); diff --git a/lib/wasi/src/syscalls/wasi/path_create_directory.rs b/lib/wasi/src/syscalls/wasi/path_create_directory.rs index 99278e49a51..473bc0e1f72 100644 --- a/lib/wasi/src/syscalls/wasi/path_create_directory.rs +++ b/lib/wasi/src/syscalls/wasi/path_create_directory.rs @@ -22,7 +22,7 @@ pub fn path_create_directory( path_len: M::Offset, ) -> Errno { let env = ctx.data(); - let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let working_dir = wasi_try!(state.fs.get_fd(fd)); { diff --git a/lib/wasi/src/syscalls/wasi/path_filestat_get.rs b/lib/wasi/src/syscalls/wasi/path_filestat_get.rs index 1750c6811b3..4941f62ee3a 100644 --- a/lib/wasi/src/syscalls/wasi/path_filestat_get.rs +++ b/lib/wasi/src/syscalls/wasi/path_filestat_get.rs @@ -26,7 +26,7 @@ pub fn path_filestat_get( buf: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let mut path_string = unsafe { get_input_str!(&memory, path, path_len) }; @@ -106,7 +106,7 @@ pub fn path_filestat_get_old( buf: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let mut path_string = unsafe { get_input_str!(&memory, path, path_len) }; diff --git a/lib/wasi/src/syscalls/wasi/path_filestat_set_times.rs b/lib/wasi/src/syscalls/wasi/path_filestat_set_times.rs index 2af25ede982..93e3accc57a 100644 --- a/lib/wasi/src/syscalls/wasi/path_filestat_set_times.rs +++ b/lib/wasi/src/syscalls/wasi/path_filestat_set_times.rs @@ -30,7 +30,7 @@ pub fn path_filestat_set_times( fst_flags: Fstflags, ) -> Errno { let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let fd_entry = wasi_try!(state.fs.get_fd(fd)); let fd_inode = fd_entry.inode; if !fd_entry.rights.contains(Rights::PATH_FILESTAT_SET_TIMES) { diff --git a/lib/wasi/src/syscalls/wasi/path_link.rs b/lib/wasi/src/syscalls/wasi/path_link.rs index 14be958d3a3..dfbdc3869b2 100644 --- a/lib/wasi/src/syscalls/wasi/path_link.rs +++ b/lib/wasi/src/syscalls/wasi/path_link.rs @@ -33,7 +33,7 @@ pub fn path_link( Span::current().record("follow_symlinks", true); } let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let mut old_path_str = unsafe { get_input_str!(&memory, old_path, old_path_len) }; Span::current().record("old_path", old_path_str.as_str()); let mut new_path_str = unsafe { get_input_str!(&memory, new_path, new_path_len) }; diff --git a/lib/wasi/src/syscalls/wasi/path_open.rs b/lib/wasi/src/syscalls/wasi/path_open.rs index ac45fde6a11..10e50922f07 100644 --- a/lib/wasi/src/syscalls/wasi/path_open.rs +++ b/lib/wasi/src/syscalls/wasi/path_open.rs @@ -42,7 +42,8 @@ pub fn path_open( Span::current().record("follow_symlinks", true); } let env = ctx.data(); - let (memory, mut state, mut inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, mut inodes) = + unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; /* TODO: find actual upper bound on name size (also this is a path, not a name :think-fish:) */ let path_len64: u64 = path_len.into(); if path_len64 > 1024u64 * 1024u64 { diff --git a/lib/wasi/src/syscalls/wasi/path_readlink.rs b/lib/wasi/src/syscalls/wasi/path_readlink.rs index ac320c55620..e83589008f9 100644 --- a/lib/wasi/src/syscalls/wasi/path_readlink.rs +++ b/lib/wasi/src/syscalls/wasi/path_readlink.rs @@ -28,7 +28,7 @@ pub fn path_readlink( buf_used: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let base_dir = wasi_try!(state.fs.get_fd(dir_fd)); if !base_dir.rights.contains(Rights::PATH_READLINK) { diff --git a/lib/wasi/src/syscalls/wasi/path_remove_directory.rs b/lib/wasi/src/syscalls/wasi/path_remove_directory.rs index 0a22520d44b..6eb72b1786c 100644 --- a/lib/wasi/src/syscalls/wasi/path_remove_directory.rs +++ b/lib/wasi/src/syscalls/wasi/path_remove_directory.rs @@ -11,7 +11,7 @@ pub fn path_remove_directory( ) -> Errno { // TODO check if fd is a dir, ensure it's within sandbox, etc. let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let base_dir = wasi_try!(state.fs.get_fd(fd)); let mut path_str = unsafe { get_input_str!(&memory, path, path_len) }; diff --git a/lib/wasi/src/syscalls/wasi/path_rename.rs b/lib/wasi/src/syscalls/wasi/path_rename.rs index 67100b6879c..2dc232a516c 100644 --- a/lib/wasi/src/syscalls/wasi/path_rename.rs +++ b/lib/wasi/src/syscalls/wasi/path_rename.rs @@ -27,7 +27,7 @@ pub fn path_rename( new_path_len: M::Offset, ) -> Errno { let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let mut source_str = unsafe { get_input_str!(&memory, old_path, old_path_len) }; Span::current().record("old_path", source_str.as_str()); source_str = ctx.data().state.fs.relative_path_to_absolute(source_str); diff --git a/lib/wasi/src/syscalls/wasi/path_symlink.rs b/lib/wasi/src/syscalls/wasi/path_symlink.rs index a03b13afa44..9e5f55c9594 100644 --- a/lib/wasi/src/syscalls/wasi/path_symlink.rs +++ b/lib/wasi/src/syscalls/wasi/path_symlink.rs @@ -24,7 +24,7 @@ pub fn path_symlink( new_path_len: M::Offset, ) -> Errno { let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let mut old_path_str = unsafe { get_input_str!(&memory, old_path, old_path_len) }; Span::current().record("old_path", old_path_str.as_str()); let mut new_path_str = unsafe { get_input_str!(&memory, new_path, new_path_len) }; diff --git a/lib/wasi/src/syscalls/wasi/path_unlink_file.rs b/lib/wasi/src/syscalls/wasi/path_unlink_file.rs index eaac44916e5..218b3993fc1 100644 --- a/lib/wasi/src/syscalls/wasi/path_unlink_file.rs +++ b/lib/wasi/src/syscalls/wasi/path_unlink_file.rs @@ -18,7 +18,7 @@ pub fn path_unlink_file( path_len: M::Offset, ) -> Errno { let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let base_dir = wasi_try!(state.fs.get_fd(fd)); if !base_dir.rights.contains(Rights::PATH_UNLINK_FILE) { diff --git a/lib/wasi/src/syscalls/wasi/poll_oneoff.rs b/lib/wasi/src/syscalls/wasi/poll_oneoff.rs index c3b89384af6..914f97fd5ce 100644 --- a/lib/wasi/src/syscalls/wasi/poll_oneoff.rs +++ b/lib/wasi/src/syscalls/wasi/poll_oneoff.rs @@ -1,6 +1,5 @@ -use std::f32::consts::E; - -use wasmer_wasix_types::wasi::SubscriptionClock; +use serde::{Deserialize, Serialize}; +use wasmer_wasix_types::wasi::{SubscriptionClock, Userdata}; use super::*; use crate::{ @@ -10,6 +9,39 @@ use crate::{ WasiInodes, }; +/// An event that occurred. +#[derive(Serialize, Deserialize)] +pub enum EventResultType { + Clock(u8), + Fd(EventFdReadwrite), +} + +/// An event that occurred. +#[derive(Serialize, Deserialize)] +pub struct EventResult { + /// User-provided value that got attached to `subscription::userdata`. + pub userdata: Userdata, + /// If non-zero, an error that occurred while processing the subscription request. + pub error: Errno, + /// Type of event that was triggered + pub type_: Eventtype, + /// The type of the event that occurred, and the contents of the event + pub inner: EventResultType, +} +impl EventResult { + pub fn into_event(self) -> Event { + Event { + userdata: self.userdata, + error: self.error, + type_: self.type_, + u: match self.inner { + EventResultType::Clock(id) => EventUnion { clock: id }, + EventResultType::Fd(fd) => EventUnion { fd_readwrite: fd }, + }, + } + } +} + /// ### `poll_oneoff()` /// Concurrently poll for a set of events /// Inputs: @@ -34,7 +66,7 @@ pub fn poll_oneoff( ctx.data_mut().poll_seed += 1; let mut env = ctx.data(); - let mut memory = env.memory_view(&ctx); + let mut memory = unsafe { env.memory_view(&ctx) }; let subscription_array = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions)); let mut subscriptions = Vec::with_capacity(subscription_array.len() as usize); @@ -49,17 +81,19 @@ pub fn poll_oneoff( wasi_try_mem_ok!(nevents.write(&memory, M::ZERO)); // Function to invoke once the poll is finished - let process_events = move |memory: &'_ Memory, store: &'_ dyn AsStoreRef, triggered_events| { + let process_events = |ctx: &FunctionEnvMut<'_, WasiEnv>, triggered_events: Vec| { + let mut env = ctx.data(); + let mut memory = unsafe { env.memory_view(&ctx) }; + // Process all the events that were triggered - let mut view = memory.view(store); let mut events_seen: u32 = 0; - let event_array = wasi_try_mem!(out_.slice(&view, nsubscriptions)); + let event_array = wasi_try_mem!(out_.slice(&memory, nsubscriptions)); for event in triggered_events { wasi_try_mem!(event_array.index(events_seen as u64).write(event)); events_seen += 1; } let events_seen: M::Offset = wasi_try!(events_seen.try_into().map_err(|_| Errno::Overflow)); - let out_ptr = nevents.deref(&view); + let out_ptr = nevents.deref(&memory); wasi_try_mem!(out_ptr.write(events_seen)); Errno::Success }; @@ -88,7 +122,7 @@ impl PollBatch { } } impl Future for PollBatch { - type Output = Result, Errno>; + type Output = Result, Errno>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let pid = self.pid; let tid = self.tid; @@ -136,18 +170,15 @@ impl Future for PollBatch { /// Output: /// - `u32 nevents` /// The number of events seen -pub(crate) fn poll_oneoff_internal( - mut ctx: FunctionEnvMut<'_, WasiEnv>, +pub(crate) fn poll_oneoff_internal<'a, M: MemorySize, After>( + mut ctx: FunctionEnvMut<'a, WasiEnv>, mut subs: Vec<(Option, PollEventSet, Subscription)>, process_events: After, ) -> Result where - After: FnOnce(&'_ Memory, &'_ dyn AsStoreRef, Vec) -> Errno + Send + Sync + 'static, + After: FnOnce(&FunctionEnvMut<'a, WasiEnv>, Vec) -> Errno, { wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); - if handle_rewind::(&mut ctx) { - return Ok(Errno::Success); - } let pid = ctx.data().pid(); let tid = ctx.data().tid(); @@ -155,6 +186,7 @@ where // Determine if we are in silent polling mode let mut env = ctx.data(); let state = ctx.data().state.deref(); + let memory = unsafe { env.memory_view(&ctx) }; // These are used when we capture what clocks (timeouts) are being // subscribed too @@ -167,7 +199,9 @@ where // First we extract all the subscriptions into an array so that they // can be processed - let mut memory = env.memory_view(&ctx); + let mut env = ctx.data(); + let state = ctx.data().state.deref(); + let mut memory = unsafe { env.memory_view(&ctx) }; for (fd, peb, s) in subs.iter_mut() { let fd = match s.type_ { Eventtype::FdRead => { @@ -301,7 +335,7 @@ where }; // If the time is infinite then we omit the time_to_sleep parameter - let asyncify_time = match time_to_sleep { + let timeout = match time_to_sleep { Duration::ZERO => { Span::current().record("timeout_ns", "nonblocking"); Some(Duration::ZERO) @@ -315,15 +349,28 @@ where Some(time) } }; + let tasks = env.tasks().clone(); + let timeout = async move { + if let Some(timeout) = timeout { + tasks.sleep_now(timeout).await; + } else { + InfiniteSleep::default().await + } + }; - // We use asyncify with a deep sleep to wait on new IO events - let res = __asyncify_with_deep_sleep_ext::( - ctx, - asyncify_time, - Duration::from_millis(50), - batch, - move |memory, store, res| { - let events = res.unwrap_or_else(Err); + // Build the trigger using the timeout + let trigger = async move { + tokio::select! { + res = batch => res, + _ = timeout => Err(Errno::Timedout) + } + }; + + // We replace the process events callback with another callback + // which will interpret the error codes + let process_events = { + let clock_subs = clock_subs.clone(); + |ctx: &FunctionEnvMut<'a, WasiEnv>, events: Result, Errno>| { // Process the result match events { Ok(evts) => { @@ -331,7 +378,7 @@ where Span::current().record("seen", evts.len()); // Process the events - process_events(memory, store, evts); + process_events(ctx, evts) } Err(Errno::Timedout) => { // The timeout has triggerred so lets add that event @@ -355,19 +402,35 @@ where ); evts.push(evt); } - process_events(memory, store, evts); + process_events(ctx, evts) } // If nonblocking the Errno::Again needs to be turned into an empty list - Err(Errno::Again) => { - process_events(memory, store, Default::default()); - } + Err(Errno::Again) => process_events(ctx, Default::default()), // Otherwise process the error Err(err) => { tracing::warn!("failed to poll during deep sleep - {}", err); + err } } - Ok(()) - }, + } + }; + + // If we are rewound then its time to process them + if let Some(events) = unsafe { handle_rewind::, Errno>>(&mut ctx) } { + let events = events.map(|events| events.into_iter().map(EventResult::into_event).collect()); + process_events(&ctx, events); + return Ok(Errno::Success); + } + + // We use asyncify with a deep sleep to wait on new IO events + let res = __asyncify_with_deep_sleep::, Errno>, _>( + ctx, + Duration::from_millis(50), + Box::pin(trigger), )?; + if let AsyncifyAction::Finish(mut ctx, events) = res { + let events = events.map(|events| events.into_iter().map(EventResult::into_event).collect()); + process_events(&ctx, events); + } Ok(Errno::Success) } diff --git a/lib/wasi/src/syscalls/wasi/proc_exit.rs b/lib/wasi/src/syscalls/wasi/proc_exit.rs index ef3122dc7ad..58b83d54b4d 100644 --- a/lib/wasi/src/syscalls/wasi/proc_exit.rs +++ b/lib/wasi/src/syscalls/wasi/proc_exit.rs @@ -20,57 +20,28 @@ pub fn proc_exit( // Restore the WasiEnv to the point when we vforked vfork.env.swap_inner(ctx.data_mut()); std::mem::swap(vfork.env.as_mut(), ctx.data_mut()); - let mut wasi_env = *vfork.env; - wasi_env.owned_handles.push(vfork.handle); + let mut child_env = *vfork.env; + child_env.owned_handles.push(vfork.handle); - // The child environment needs to be notified as exited - wasi_env.thread.set_status_finished(Ok(code)); - - // We still need to create the process that exited so that - // the exit code can be used by the parent process - let pid = wasi_env.process.pid(); - let mut memory_stack = vfork.memory_stack; - let rewind_stack = vfork.rewind_stack; - let store_data = vfork.store_data; - - // If the return value offset is within the memory stack then we need - // to update it here rather than in the real memory - let val_bytes = pid.raw().to_ne_bytes(); - let pid_offset: u64 = vfork.pid_offset; - if pid_offset >= wasi_env.layout.stack_lower - && (pid_offset + val_bytes.len() as u64) <= wasi_env.layout.stack_upper - { - // Make sure its within the "active" part of the memory stack - let offset = wasi_env.layout().stack_upper - pid_offset; - if (offset as usize + val_bytes.len()) > memory_stack.len() { - warn!( - "fork failed - the return value (pid) is outside of the active part of the memory stack ({} vs {})", - offset, - memory_stack.len() - ); - return Err(WasiError::Exit(Errno::Memviolation.into())); - } - - // Update the memory stack with the new PID - let pstart = memory_stack.len() - offset as usize; - let pend = pstart + val_bytes.len(); - let pbytes = &mut memory_stack[pstart..pend]; - pbytes.clone_from_slice(&val_bytes); - } else { - warn!( - "fork failed - the return value (pid) is not being returned on the stack - which is not supported" - ); - return Err(WasiError::Exit(Errno::Memviolation.into())); - } + // Terminate the child process + child_env.process.terminate(code); // Jump back to the vfork point and current on execution + let child_pid = child_env.process.pid(); + let memory_stack = vfork.memory_stack.freeze(); + let rewind_stack = vfork.rewind_stack.freeze(); + let store_data = vfork.store_data; unwind::(ctx, move |mut ctx, _, _| { // Now rewind the previous stack and carry on from where we did the vfork - match rewind::( + match rewind::( ctx, - memory_stack.freeze(), - rewind_stack.freeze(), + memory_stack, + rewind_stack, store_data, + ForkResult { + pid: child_pid.raw() as Pid, + ret: Errno::Success, + }, ) { Errno::Success => OnCalledAction::InvokeAgain, err => { diff --git a/lib/wasi/src/syscalls/wasi/random_get.rs b/lib/wasi/src/syscalls/wasi/random_get.rs index 06b65cac446..f8c3153d085 100644 --- a/lib/wasi/src/syscalls/wasi/random_get.rs +++ b/lib/wasi/src/syscalls/wasi/random_get.rs @@ -15,7 +15,7 @@ pub fn random_get( buf_len: M::Offset, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let buf_len64: u64 = buf_len.into(); let mut u8_buffer = vec![0; buf_len64 as usize]; let res = getrandom::getrandom(&mut u8_buffer); diff --git a/lib/wasi/src/syscalls/wasix/callback_reactor.rs b/lib/wasi/src/syscalls/wasix/callback_reactor.rs index 57f17556964..570da20208e 100644 --- a/lib/wasi/src/syscalls/wasix/callback_reactor.rs +++ b/lib/wasi/src/syscalls/wasix/callback_reactor.rs @@ -14,18 +14,17 @@ pub fn callback_reactor( name_len: M::Offset, ) -> Result<(), MemoryAccessError> { let env = ctx.data(); - let memory = env.memory_view(&ctx); - let name = unsafe { name.read_utf8_string(&memory, name_len)? }; + let memory = unsafe { env.memory_view(&ctx) }; + let name = name.read_utf8_string(&memory, name_len)?; Span::current().record("name", name.as_str()); - let funct = env - .inner() + let funct = unsafe { env.inner() } .instance .exports .get_typed_function(&ctx, &name) .ok(); Span::current().record("funct_is_some", funct.is_some()); - ctx.data_mut().inner_mut().react = funct; + ctx.data_mut().try_inner_mut().unwrap().react = funct; Ok(()) } diff --git a/lib/wasi/src/syscalls/wasix/callback_signal.rs b/lib/wasi/src/syscalls/wasix/callback_signal.rs index 5dc6e3c644b..eb5e1239e42 100644 --- a/lib/wasi/src/syscalls/wasix/callback_signal.rs +++ b/lib/wasi/src/syscalls/wasix/callback_signal.rs @@ -14,23 +14,20 @@ pub fn callback_signal( name_len: M::Offset, ) -> Result<(), WasiError> { let env = ctx.data(); - let memory = env.memory_view(&ctx); - let name = unsafe { - match name.read_utf8_string(&memory, name_len) { - Ok(a) => a, - Err(err) => { - warn!( - "failed to access memory that holds the name of the signal callback: {}", - err - ); - return Ok(()); - } + let memory = unsafe { env.memory_view(&ctx) }; + let name = match name.read_utf8_string(&memory, name_len) { + Ok(a) => a, + Err(err) => { + warn!( + "failed to access memory that holds the name of the signal callback: {}", + err + ); + return Ok(()); } }; Span::current().record("name", name.as_str()); - let funct = env - .inner() + let funct = unsafe { env.inner() } .instance .exports .get_typed_function(&ctx, &name) @@ -38,12 +35,12 @@ pub fn callback_signal( Span::current().record("funct_is_some", funct.is_some()); { - let mut inner = ctx.data_mut().inner_mut(); + let mut inner = ctx.data_mut().try_inner_mut().unwrap(); inner.signal = funct; inner.signal_set = true; } - let _ = WasiEnv::process_signals_and_exit(&mut ctx)?; + let _ = unsafe { WasiEnv::process_signals_and_exit(&mut ctx)? }; Ok(()) } diff --git a/lib/wasi/src/syscalls/wasix/callback_thread.rs b/lib/wasi/src/syscalls/wasix/callback_thread.rs index 89b23bd18e1..07824ffd8a8 100644 --- a/lib/wasi/src/syscalls/wasix/callback_thread.rs +++ b/lib/wasi/src/syscalls/wasix/callback_thread.rs @@ -14,19 +14,18 @@ pub fn callback_thread( name_len: M::Offset, ) -> Result<(), MemoryAccessError> { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; - let name = unsafe { name.read_utf8_string(&memory, name_len)? }; + let name = name.read_utf8_string(&memory, name_len)?; Span::current().record("name", name.as_str()); - let funct = env - .inner() + let funct = unsafe { env.inner() } .instance .exports .get_typed_function(&ctx, &name) .ok(); Span::current().record("funct_is_some", funct.is_some()); - ctx.data_mut().inner_mut().thread_spawn = funct; + ctx.data_mut().try_inner_mut().unwrap().thread_spawn = funct; Ok(()) } diff --git a/lib/wasi/src/syscalls/wasix/callback_thread_local_destroy.rs b/lib/wasi/src/syscalls/wasix/callback_thread_local_destroy.rs index 9e39550b351..74c60781cf7 100644 --- a/lib/wasi/src/syscalls/wasix/callback_thread_local_destroy.rs +++ b/lib/wasi/src/syscalls/wasix/callback_thread_local_destroy.rs @@ -14,19 +14,18 @@ pub fn callback_thread_local_destroy( name_len: M::Offset, ) -> Result<(), MemoryAccessError> { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; - let name = unsafe { name.read_utf8_string(&memory, name_len)? }; + let name = name.read_utf8_string(&memory, name_len)?; Span::current().record("name", name.as_str()); - let funct = env - .inner() + let funct = unsafe { env.inner() } .instance .exports .get_typed_function(&ctx, &name) .ok(); Span::current().record("funct_is_some", funct.is_some()); - ctx.data_mut().inner_mut().thread_local_destroy = funct; + ctx.data_mut().try_inner_mut().unwrap().thread_local_destroy = funct; Ok(()) } diff --git a/lib/wasi/src/syscalls/wasix/chdir.rs b/lib/wasi/src/syscalls/wasix/chdir.rs index 58e66963f38..2816c8c7ee8 100644 --- a/lib/wasi/src/syscalls/wasix/chdir.rs +++ b/lib/wasi/src/syscalls/wasix/chdir.rs @@ -10,7 +10,7 @@ pub fn chdir( path_len: M::Offset, ) -> Errno { let env = ctx.data(); - let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); + let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) }; let path = unsafe { get_input_str!(&memory, path, path_len) }; Span::current().record("path", path.as_str()); diff --git a/lib/wasi/src/syscalls/wasix/fd_pipe.rs b/lib/wasi/src/syscalls/wasix/fd_pipe.rs index 99db209d1cb..ea0cad30f4a 100644 --- a/lib/wasi/src/syscalls/wasix/fd_pipe.rs +++ b/lib/wasi/src/syscalls/wasix/fd_pipe.rs @@ -17,7 +17,7 @@ pub fn fd_pipe( ro_fd2: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let (pipe1, pipe2) = Pipe::channel(); diff --git a/lib/wasi/src/syscalls/wasix/futex_wait.rs b/lib/wasi/src/syscalls/wasix/futex_wait.rs index 570465f3f33..44b93d3bc6e 100644 --- a/lib/wasi/src/syscalls/wasix/futex_wait.rs +++ b/lib/wasi/src/syscalls/wasix/futex_wait.rs @@ -3,32 +3,43 @@ use std::task::Waker; use super::*; use crate::syscalls::*; -#[derive(Clone)] +/// Poller returns true if its triggered and false if it times out struct FutexPoller { state: Arc, poller_idx: u64, futex_idx: u64, expected: u32, + timeout: Option + Send + Sync + 'static>>>, } impl Future for FutexPoller { - type Output = Result<(), Errno>; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + type Output = bool; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut guard = self.state.futexs.lock().unwrap(); // If the futex itself is no longer registered then it was likely // woken by a wake call let futex = match guard.futexes.get_mut(&self.futex_idx) { Some(f) => f, - None => return Poll::Ready(Ok(())), + None => return Poll::Ready(true), }; let waker = match futex.wakers.get_mut(&self.poller_idx) { Some(w) => w, - None => return Poll::Ready(Ok(())), + None => return Poll::Ready(true), }; // Register the waker waker.replace(cx.waker().clone()); + // Check for timeout + drop(guard); + if let Some(timeout) = self.timeout.as_mut() { + let timeout = timeout.as_mut(); + if timeout.poll(cx).is_ready() { + self.timeout.take(); + return Poll::Ready(false); + } + } + // We will now wait to be woken Poll::Pending } @@ -50,45 +61,6 @@ impl Drop for FutexPoller { } } -/// The futex after struct will write the response of whether the -/// futex was actually woken or not to the return memory of the syscall -/// callee after the wake event has been triggered. -/// -/// It is encased in this struct so that it can be passed around -/// between threads and execute after the threads are rewound (in an -/// asynchronous threading situation). -/// -/// The same implementation is used for both synchronous and -/// asynchronous threading. -/// -/// It is not possible to include this logic directly in the poller -/// as the poller runs before the stack is rewound and the memory -/// that this writes to is often a pointer to the stack hence a -/// rewind would override whatever is written. -struct FutexAfter -where - M: MemorySize, -{ - ret_woken: WasmPtr, -} -impl RewindPostProcess for FutexAfter -where - M: MemorySize, -{ - fn finish( - &mut self, - env: &WasiEnv, - store: &dyn AsStoreRef, - res: Result<(), Errno>, - ) -> Result<(), ExitCode> { - let view = env.memory_view(store); - self.ret_woken - .write(&view, Bool::True) - .map_err(mem_error_to_wasi) - .map_err(ExitCode::Errno) - } -} - /// Wait for a futex_wake operation to wake us. /// Returns with EINVAL if the futex doesn't hold the expected value. /// Returns false on timeout, and true in all other cases. @@ -98,7 +70,7 @@ where /// * `futex` - Memory location that holds the value that will be checked /// * `expected` - Expected value that should be currently held at the memory location /// * `timeout` - Timeout should the futex not be triggered in the allocated time -#[instrument(level = "trace", skip_all, fields(futex_idx = field::Empty, poller_idx = field::Empty, %expected, timeout = field::Empty, woken = field::Empty), err)] +//#[instrument(level = "trace", skip_all, fields(futex_idx = field::Empty, poller_idx = field::Empty, %expected, timeout = field::Empty, woken = field::Empty), err)] pub fn futex_wait( mut ctx: FunctionEnvMut<'_, WasiEnv>, futex_ptr: WasmPtr, @@ -112,7 +84,7 @@ pub fn futex_wait( // and thus we repeat all the checks again, we do not immediately // exit here as it could be the case that we were woken but the // expected value does not match - if handle_rewind::(&mut ctx) { + if let Some(_woken) = unsafe { handle_rewind::(&mut ctx) } { // fall through so the normal checks kick in, this will // ensure that the expected value has changed before // this syscall returns even if it was woken @@ -121,7 +93,7 @@ pub fn futex_wait( // Determine the timeout let mut env = ctx.data(); let timeout = { - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem_ok!(timeout.read(&memory)) }; let timeout = match timeout.tag { @@ -144,6 +116,9 @@ pub fn futex_wait( guard.poller_seed += 1; let poller_idx = guard.poller_seed; + // Create the timeout if one exists + let timeout = timeout.map(|timeout| env.tasks().sleep_now(timeout)); + // We insert the futex before we check the condition variable to avoid // certain race conditions let futex = guard.futexes.entry(futex_idx).or_default(); @@ -155,11 +130,12 @@ pub fn futex_wait( poller_idx, futex_idx, expected, + timeout, } }; // We check if the expected value has changed - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let val = wasi_try_mem_ok!(futex_ptr.read(&memory)); if val != expected { // We have been triggered so do not go into a wait @@ -171,17 +147,17 @@ pub fn futex_wait( // then the value is not set) - the poller will set it to true wasi_try_mem_ok!(ret_woken.write(&memory, Bool::False)); - // Create a poller which will register ourselves against - // this futex event and check when it has changed - let after = FutexAfter { ret_woken }; - // We use asyncify on the poller and potentially go into deep sleep - __asyncify_with_deep_sleep::( - ctx, - timeout, - Duration::from_millis(50), - Box::pin(poller), - after, - )?; + let res = + __asyncify_with_deep_sleep::(ctx, Duration::from_millis(50), Box::pin(poller))?; + if let AsyncifyAction::Finish(ctx, res) = res { + let mut env = ctx.data(); + let memory = unsafe { env.memory_view(&ctx) }; + if res { + wasi_try_mem_ok!(ret_woken.write(&memory, Bool::True)); + } else { + wasi_try_mem_ok!(ret_woken.write(&memory, Bool::False)); + } + } Ok(Errno::Success) } diff --git a/lib/wasi/src/syscalls/wasix/futex_wake.rs b/lib/wasi/src/syscalls/wasix/futex_wake.rs index 63d754ac796..aad19b64613 100644 --- a/lib/wasi/src/syscalls/wasix/futex_wake.rs +++ b/lib/wasi/src/syscalls/wasix/futex_wake.rs @@ -15,7 +15,7 @@ pub fn futex_wake( ret_woken: WasmPtr, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let state = env.state.deref(); let pointer: u64 = wasi_try!(futex_ptr.offset().try_into().map_err(|_| Errno::Overflow)); diff --git a/lib/wasi/src/syscalls/wasix/futex_wake_all.rs b/lib/wasi/src/syscalls/wasix/futex_wake_all.rs index ad943558868..5365b90ff53 100644 --- a/lib/wasi/src/syscalls/wasix/futex_wake_all.rs +++ b/lib/wasi/src/syscalls/wasix/futex_wake_all.rs @@ -13,7 +13,7 @@ pub fn futex_wake_all( ret_woken: WasmPtr, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let state = env.state.deref(); let pointer: u64 = wasi_try!(futex_ptr.offset().try_into().map_err(|_| Errno::Overflow)); diff --git a/lib/wasi/src/syscalls/wasix/getcwd.rs b/lib/wasi/src/syscalls/wasix/getcwd.rs index 5df0f8bf825..27250221a85 100644 --- a/lib/wasi/src/syscalls/wasix/getcwd.rs +++ b/lib/wasi/src/syscalls/wasix/getcwd.rs @@ -12,7 +12,7 @@ pub fn getcwd( path_len: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let (_, cur_dir) = wasi_try!(state.fs.get_current_dir(inodes, crate::VIRTUAL_ROOT_FD,)); Span::current().record("path", cur_dir.as_str()); diff --git a/lib/wasi/src/syscalls/wasix/port_addr_add.rs b/lib/wasi/src/syscalls/wasix/port_addr_add.rs index 5a87a5b4ac1..1bfa433f88d 100644 --- a/lib/wasi/src/syscalls/wasix/port_addr_add.rs +++ b/lib/wasi/src/syscalls/wasix/port_addr_add.rs @@ -13,7 +13,7 @@ pub fn port_addr_add( ip: WasmPtr<__wasi_cidr_t, M>, ) -> Result { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let cidr = wasi_try_ok!(crate::net::read_cidr(&memory, ip)); Span::current().record("ip", &format!("{:?}", cidr)); diff --git a/lib/wasi/src/syscalls/wasix/port_addr_list.rs b/lib/wasi/src/syscalls/wasix/port_addr_list.rs index cb4b49ca27c..b48a45f5fc4 100644 --- a/lib/wasi/src/syscalls/wasix/port_addr_list.rs +++ b/lib/wasi/src/syscalls/wasix/port_addr_list.rs @@ -21,7 +21,7 @@ pub fn port_addr_list( naddrs_ptr: WasmPtr, ) -> Result { let mut env = ctx.data(); - let mut memory = env.memory_view(&ctx); + let mut memory = unsafe { env.memory_view(&ctx) }; let max_addrs = wasi_try_mem_ok!(naddrs_ptr.read(&memory)); let max_addrs: u64 = wasi_try_ok!(max_addrs.try_into().map_err(|_| Errno::Overflow)); @@ -30,7 +30,7 @@ pub fn port_addr_list( net.ip_list().map_err(net_error_into_wasi_err) })?); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; Span::current().record("naddrs", addrs.len()); let addrs_len: M::Offset = wasi_try_ok!(addrs.len().try_into().map_err(|_| Errno::Overflow)); diff --git a/lib/wasi/src/syscalls/wasix/port_addr_remove.rs b/lib/wasi/src/syscalls/wasix/port_addr_remove.rs index 08548048217..daab635c614 100644 --- a/lib/wasi/src/syscalls/wasix/port_addr_remove.rs +++ b/lib/wasi/src/syscalls/wasix/port_addr_remove.rs @@ -13,7 +13,7 @@ pub fn port_addr_remove( ip: WasmPtr<__wasi_addr_t, M>, ) -> Result { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let ip = wasi_try_ok!(crate::net::read_ip(&memory, ip)); Span::current().record("ip", &format!("{:?}", ip)); diff --git a/lib/wasi/src/syscalls/wasix/port_bridge.rs b/lib/wasi/src/syscalls/wasix/port_bridge.rs index 1a3a5320349..28aa712bf46 100644 --- a/lib/wasi/src/syscalls/wasix/port_bridge.rs +++ b/lib/wasi/src/syscalls/wasix/port_bridge.rs @@ -19,7 +19,7 @@ pub fn port_bridge( security: Streamsecurity, ) -> Result { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let network = unsafe { get_input_str_ok!(&memory, network, network_len) }; Span::current().record("network", network.as_str()); diff --git a/lib/wasi/src/syscalls/wasix/port_gateway_set.rs b/lib/wasi/src/syscalls/wasix/port_gateway_set.rs index 29bdee1a8ad..ecb9a8c8a28 100644 --- a/lib/wasi/src/syscalls/wasix/port_gateway_set.rs +++ b/lib/wasi/src/syscalls/wasix/port_gateway_set.rs @@ -13,7 +13,7 @@ pub fn port_gateway_set( ip: WasmPtr<__wasi_addr_t, M>, ) -> Result { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let ip = wasi_try_ok!(crate::net::read_ip(&memory, ip)); Span::current().record("ip", &format!("{:?}", ip)); diff --git a/lib/wasi/src/syscalls/wasix/port_mac.rs b/lib/wasi/src/syscalls/wasix/port_mac.rs index d46751114a3..2bd39294e1b 100644 --- a/lib/wasi/src/syscalls/wasix/port_mac.rs +++ b/lib/wasi/src/syscalls/wasix/port_mac.rs @@ -9,14 +9,14 @@ pub fn port_mac( ret_mac: WasmPtr<__wasi_hardwareaddress_t, M>, ) -> Result { let mut env = ctx.data(); - let mut memory = env.memory_view(&ctx); + let mut memory = unsafe { env.memory_view(&ctx) }; let net = env.net().clone(); let mac = wasi_try_ok!(__asyncify(&mut ctx, None, async { net.mac().map_err(net_error_into_wasi_err) })?); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; Span::current().record("mac", hex::encode(mac.as_ref()).as_str()); diff --git a/lib/wasi/src/syscalls/wasix/port_route_add.rs b/lib/wasi/src/syscalls/wasix/port_route_add.rs index e8180ec7529..db85e487298 100644 --- a/lib/wasi/src/syscalls/wasix/port_route_add.rs +++ b/lib/wasi/src/syscalls/wasix/port_route_add.rs @@ -12,7 +12,7 @@ pub fn port_route_add( expires_at: WasmPtr, ) -> Result { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let cidr = wasi_try_ok!(crate::net::read_cidr(&memory, cidr)); Span::current().record("cidr", &format!("{:?}", cidr)); diff --git a/lib/wasi/src/syscalls/wasix/port_route_list.rs b/lib/wasi/src/syscalls/wasix/port_route_list.rs index eec6d1184c4..cb10d087ccc 100644 --- a/lib/wasi/src/syscalls/wasix/port_route_list.rs +++ b/lib/wasi/src/syscalls/wasix/port_route_list.rs @@ -17,7 +17,7 @@ pub fn port_route_list( nroutes_ptr: WasmPtr, ) -> Result { let mut env = ctx.data(); - let mut memory = env.memory_view(&ctx); + let mut memory = unsafe { env.memory_view(&ctx) }; let ref_nroutes = nroutes_ptr.deref(&memory); let max_routes: usize = wasi_try_ok!(wasi_try_mem_ok!(ref_nroutes.read()) .try_into() @@ -33,7 +33,7 @@ pub fn port_route_list( Span::current().record("nroutes", routes.len()); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let routes_len: M::Offset = wasi_try_ok!(routes.len().try_into().map_err(|_| Errno::Inval)); let nroutes = nroutes_ptr.deref(&memory); diff --git a/lib/wasi/src/syscalls/wasix/port_route_remove.rs b/lib/wasi/src/syscalls/wasix/port_route_remove.rs index 942c8d41687..52068c032e6 100644 --- a/lib/wasi/src/syscalls/wasix/port_route_remove.rs +++ b/lib/wasi/src/syscalls/wasix/port_route_remove.rs @@ -9,7 +9,7 @@ pub fn port_route_remove( ip: WasmPtr<__wasi_addr_t, M>, ) -> Result { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let ip = wasi_try_ok!(crate::net::read_ip(&memory, ip)); Span::current().record("ip", &format!("{:?}", ip)); diff --git a/lib/wasi/src/syscalls/wasix/proc_exec.rs b/lib/wasi/src/syscalls/wasix/proc_exec.rs index 4824480ea84..9a89a5e5b60 100644 --- a/lib/wasi/src/syscalls/wasix/proc_exec.rs +++ b/lib/wasi/src/syscalls/wasix/proc_exec.rs @@ -1,3 +1,5 @@ +use wasmer::FromToNativeWasmType; + use super::*; use crate::{ os::task::{OwnedTaskStatus, TaskStatus}, @@ -26,13 +28,15 @@ pub fn proc_exec( WasiEnv::process_signals_and_exit(&mut ctx)?; // If we were just restored the stack then we were woken after a deep sleep - if handle_rewind::(&mut ctx) { + if let Some(exit_code) = unsafe { handle_rewind::(&mut ctx) } { // We should never get here as the process will be termined // in the `WasiEnv::process_signals_and_exit()` call - return Err(WasiError::Exit(Errno::Unknown.into())); + let exit_code = ExitCode::from_native(exit_code); + ctx.data().process.terminate(exit_code); + return Err(WasiError::Exit(exit_code)); } - let memory = ctx.data().memory_view(&ctx); + let memory = unsafe { ctx.data().memory_view(&ctx) }; let mut name = name.read_utf8_string(&memory, name_len).map_err(|err| { warn!("failed to execve as the name could not be read - {}", err); WasiError::Exit(Errno::Inval.into()) @@ -59,7 +63,8 @@ pub fn proc_exec( // Get the current working directory let (_, cur_dir) = { - let (memory, state, inodes) = ctx.data().get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, state, inodes) = + unsafe { ctx.data().get_memory_and_wasi_state_and_inodes(&ctx, 0) }; match state.fs.get_current_dir(inodes, crate::VIRTUAL_ROOT_FD) { Ok(a) => a, Err(err) => { @@ -127,11 +132,17 @@ pub fn proc_exec( "failed to execve as the process could not be spawned (vfork) - {}", err ); - let _ = stderr_write( - &ctx, - format!("wasm execute failed [{}] - {}\n", name.as_str(), err) + let _ = unsafe { + stderr_write( + &ctx, + format!( + "wasm execute failed [{}] - {}\n", + name.as_str(), + err + ) .as_bytes(), - ) + ) + } .await; } } @@ -142,44 +153,22 @@ pub fn proc_exec( } }; - let mut memory_stack = vfork.memory_stack; - let rewind_stack = vfork.rewind_stack; - let store_data = vfork.store_data; - - // If the return value offset is within the memory stack then we need - // to update it here rather than in the real memory - let val_bytes = child_pid.raw().to_ne_bytes(); - let pid_offset: u64 = vfork.pid_offset; - if pid_offset >= stack_lower && (pid_offset + val_bytes.len() as u64) <= stack_upper { - // Make sure its within the "active" part of the memory stack - let offset = stack_upper - pid_offset; - if (offset as usize + val_bytes.len()) > memory_stack.len() { - warn!( - "vfork failed - the return value (pid) is outside of the active part of the memory stack ({} vs {})", - offset, - memory_stack.len() - ); - } else { - // Update the memory stack with the new PID - let pstart = memory_stack.len() - offset as usize; - let pend = pstart + val_bytes.len(); - let pbytes = &mut memory_stack[pstart..pend]; - pbytes.clone_from_slice(&val_bytes); - } - } else { - warn!( - "vfork failed - the return value (pid) is not being returned on the stack - which is not supported", - ); - } - // Jump back to the vfork point and current on execution + // note: fork does not return any values hence passing `()` + let memory_stack = vfork.memory_stack.freeze(); + let rewind_stack = vfork.rewind_stack.freeze(); + let store_data = vfork.store_data; unwind::(ctx, move |mut ctx, _, _| { // Rewind the stack - match rewind::( + match rewind::( ctx, - memory_stack.freeze(), - rewind_stack.freeze(), + memory_stack, + rewind_stack, store_data, + ForkResult { + pid: child_pid.raw() as Pid, + ret: Errno::Success, + }, ) { Errno::Success => OnCalledAction::InvokeAgain, err => { @@ -241,25 +230,22 @@ pub fn proc_exec( let thread = env.thread.clone(); // The poller will wait for the process to actually finish - let res = __asyncify_with_deep_sleep_ext::( + let res = __asyncify_with_deep_sleep::( ctx, - None, Duration::from_millis(50), async move { process .wait_finished() .await .unwrap_or_else(|_| Errno::Child.into()) - }, - move |_, _, res| { - let exit_code = res.unwrap_or_else(ExitCode::Errno); - thread.set_status_finished(Ok(exit_code)); - Ok(()) + .to_native() }, )?; match res { - AsyncifyAction::Finish(mut ctx) => { + AsyncifyAction::Finish(mut ctx, result) => { // When we arrive here the process should already be terminated + let exit_code = ExitCode::from_native(result); + ctx.data().process.terminate(exit_code); WasiEnv::process_signals_and_exit(&mut ctx)?; Err(WasiError::Exit(Errno::Unknown.into())) } diff --git a/lib/wasi/src/syscalls/wasix/proc_fork.rs b/lib/wasi/src/syscalls/wasix/proc_fork.rs index 35c1e3f0091..d44a93b54f4 100644 --- a/lib/wasi/src/syscalls/wasix/proc_fork.rs +++ b/lib/wasi/src/syscalls/wasix/proc_fork.rs @@ -6,8 +6,15 @@ use crate::{ syscalls::*, WasiThreadHandle, }; +use serde::{Deserialize, Serialize}; use wasmer::Memory; +#[derive(Serialize, Deserialize)] +pub(crate) struct ForkResult { + pub pid: Pid, + pub ret: Errno, +} + /// ### `proc_fork()` /// Forks the current process into a new subprocess. If the function /// returns a zero then its the new subprocess. If it returns a positive @@ -21,15 +28,15 @@ pub fn proc_fork( wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); // If we were just restored then we need to return the value instead - if handle_rewind::(&mut ctx) { - let view = ctx.data().memory_view(&ctx); - let ret_pid = pid_ptr.read(&view).unwrap_or(u32::MAX); - if ret_pid == 0 { + if let Some(result) = unsafe { handle_rewind::(&mut ctx) } { + if result.pid == 0 { trace!("handle_rewind - i am child"); } else { - trace!("handle_rewind - i am parent (child={})", ret_pid); + trace!("handle_rewind - i am parent (child={})", result.pid); } - return Ok(Errno::Success); + let memory = unsafe { ctx.data().memory_view(&ctx) }; + wasi_try_mem_ok!(pid_ptr.write(&memory, result.pid)); + return Ok(result.ret); } trace!(%copy_memory, "capturing"); @@ -55,7 +62,7 @@ pub fn proc_fork( inner.children.push(child_env.process.clone()); } let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; // Setup some properties in the child environment wasi_try_mem_ok!(pid_ptr.write(&memory, 0)); @@ -71,7 +78,6 @@ pub fn proc_fork( // actually occurs if copy_memory == Bool::False { // Perform the unwind action - let pid_offset: u64 = pid_offset.into(); return unwind::(ctx, move |mut ctx, mut memory_stack, rewind_stack| { // Grab all the globals and serialize them let store_data = crate::utils::store::capture_snapshot(&mut ctx.as_store_mut()) @@ -90,17 +96,20 @@ pub fn proc_fork( store_data: store_data.clone(), env: Box::new(child_env), handle: child_handle, - pid_offset, }); // Carry on as if the fork had taken place (which basically means // it prevents to be the new process with the old one suspended) // Rewind the stack and carry on - match rewind::( + match rewind::( ctx, memory_stack.freeze(), rewind_stack.freeze(), store_data, + ForkResult { + pid: 0, + ret: Errno::Success, + }, ) { Errno::Success => OnCalledAction::InvokeAgain, err => { @@ -135,8 +144,8 @@ pub fn proc_fork( let child_memory_stack = memory_stack.clone(); let child_rewind_stack = rewind_stack.clone(); - let module = ctx.data().inner().module_clone(); - let memory = ctx.data().memory_clone(); + let module = unsafe { ctx.data().inner() }.module_clone(); + let memory = unsafe { ctx.data().inner() }.memory_clone(); let spawn_type = SpawnMemoryType::CopyMemory(memory, ctx.as_store_ref()); // Spawn a new process with this current execution environment @@ -156,11 +165,15 @@ pub fn proc_fork( trace!("rewinding child"); let mut ctx = ctx.env.clone().into_mut(&mut store); let (data, mut store) = ctx.data_and_store_mut(); - match rewind::( + match rewind::( ctx, child_memory_stack.freeze(), child_rewind_stack.freeze(), store_data.clone(), + ForkResult { + pid: 0, + ret: Errno::Success, + }, ) { Errno::Success => OnCalledAction::InvokeAgain, err => { @@ -193,43 +206,16 @@ pub fn proc_fork( .ok() }; - // If the return value offset is within the memory stack then we need - // to update it here rather than in the real memory - let env = ctx.data(); - let val_bytes = child_pid.raw().to_ne_bytes(); - let pid_offset: u64 = pid_offset.into(); - if pid_offset >= env.layout.stack_lower - && (pid_offset + val_bytes.len() as u64) <= env.layout.stack_upper - { - // Make sure its within the "active" part of the memory stack - let offset = env.layout.stack_upper - pid_offset; - if offset as usize > memory_stack.len() { - warn!( - "failed - the return value (pid) is outside of the active part of the memory stack ({} vs {})", - offset, - memory_stack.len() - ); - return OnCalledAction::Trap(Box::new(WasiError::Exit(Errno::Memviolation.into()))); - } - - // Update the memory stack with the new PID - let pstart = memory_stack.len() - offset as usize; - let pend = pstart + val_bytes.len(); - let pbytes = &mut memory_stack[pstart..pend]; - pbytes.clone_from_slice(&val_bytes); - } else { - warn!( - "failed - the return value (pid) is not being returned on the stack - which is not supported" - ); - return OnCalledAction::Trap(Box::new(WasiError::Exit(Errno::Memviolation.into()))); - } - // Rewind the stack and carry on - match rewind::( + match rewind::( ctx, memory_stack.freeze(), rewind_stack.freeze(), store_data, + ForkResult { + pid: child_pid.raw() as Pid, + ret: Errno::Success, + }, ) { Errno::Success => OnCalledAction::InvokeAgain, err => { @@ -244,7 +230,7 @@ fn run( ctx: WasiFunctionEnv, mut store: Store, child_handle: WasiThreadHandle, - rewind_state: Option<(RewindState, Result<(), Errno>)>, + rewind_state: Option<(RewindState, Bytes)>, ) -> ExitCode { let env = ctx.data(&store); let tasks = env.tasks().clone(); @@ -252,15 +238,13 @@ fn run( let tid = env.tid(); // If we need to rewind then do so - if let Some((mut rewind_state, trigger_res)) = rewind_state { - if let Err(exit_code) = rewind_state.rewinding_finish::(&ctx, &mut store, trigger_res) { - return exit_code; - } - let res = rewind::( + if let Some((rewind_state, rewind_result)) = rewind_state { + let res = rewind_ext::( ctx.env.clone().into_mut(&mut store), rewind_state.memory_stack, rewind_state.rewind_stack, rewind_state.store_data, + rewind_result, ); if res != Errno::Success { return res.into(); @@ -270,11 +254,14 @@ fn run( let mut ret: ExitCode = Errno::Success.into(); let err = if ctx.data(&store).thread.is_main() { trace!(%pid, %tid, "re-invoking main"); - let start = ctx.data(&store).inner().start.clone().unwrap(); + let start = unsafe { ctx.data(&store).inner() }.start.clone().unwrap(); start.call(&mut store) } else { trace!(%pid, %tid, "re-invoking thread_spawn"); - let start = ctx.data(&store).inner().thread_spawn.clone().unwrap(); + let start = unsafe { ctx.data(&store).inner() } + .thread_spawn + .clone() + .unwrap(); start.call(&mut store, 0, 0) }; if let Err(err) = err { @@ -289,13 +276,20 @@ fn run( let respawn = { let tasks = tasks.clone(); let rewind_state = deep.rewind; - move |ctx, store, trigger_res| { - run::(ctx, store, child_handle, Some((rewind_state, trigger_res))); + move |ctx, store, rewind_result| { + run::( + ctx, + store, + child_handle, + Some((rewind_state, rewind_result)), + ); } }; /// Spawns the WASM process after a trigger - tasks.resume_wasm_after_poller(Box::new(respawn), ctx, store, deep.trigger); + unsafe { + tasks.resume_wasm_after_poller(Box::new(respawn), ctx, store, deep.trigger) + }; return Errno::Success.into(); } _ => {} diff --git a/lib/wasi/src/syscalls/wasix/proc_id.rs b/lib/wasi/src/syscalls/wasix/proc_id.rs index 2a84c52158f..bbbc25fb0c9 100644 --- a/lib/wasi/src/syscalls/wasix/proc_id.rs +++ b/lib/wasi/src/syscalls/wasix/proc_id.rs @@ -6,7 +6,7 @@ use crate::syscalls::*; #[instrument(level = "debug", skip_all, fields(pid = field::Empty), ret)] pub fn proc_id(ctx: FunctionEnvMut<'_, WasiEnv>, ret_pid: WasmPtr) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let pid = env.process.pid(); Span::current().record("pid", pid.raw()); diff --git a/lib/wasi/src/syscalls/wasix/proc_join.rs b/lib/wasi/src/syscalls/wasix/proc_join.rs index 856f4ffecea..41189880ff9 100644 --- a/lib/wasi/src/syscalls/wasix/proc_join.rs +++ b/lib/wasi/src/syscalls/wasix/proc_join.rs @@ -1,15 +1,24 @@ +use serde::{Deserialize, Serialize}; +use wasmer::FromToNativeWasmType; use wasmer_wasix_types::wasi::{JoinFlags, JoinStatus, JoinStatusType, JoinStatusUnion, OptionPid}; use super::*; use crate::{syscalls::*, WasiProcess}; +#[derive(Serialize, Deserialize)] +enum JoinStatusResult { + Nothing, + ExitNormal(WasiProcessId, ExitCode), + Err(Errno), +} + /// ### `proc_join()` /// Joins the child process, blocking this one until the other finishes /// /// ## Parameters /// /// * `pid` - Handle of the child process to wait on -#[instrument(level = "trace", skip_all, fields(pid = ctx.data().process.pid().raw()), ret, err)] +//#[instrument(level = "trace", skip_all, fields(pid = ctx.data().process.pid().raw()), ret, err)] pub fn proc_join( mut ctx: FunctionEnvMut<'_, WasiEnv>, pid_ptr: WasmPtr, @@ -21,38 +30,52 @@ pub fn proc_join( // This lambda will look at what we wrote in the status variable // and use this to determine the return code sent back to the caller let ret_result = { - let status_ptr = status_ptr; - move |ctx: FunctionEnvMut<'_, WasiEnv>| { - let view = ctx.data().memory_view(&ctx); - let status = wasi_try_mem_ok!(status_ptr.read(&view)); - if status.tag == JoinStatusType::Nothing { - let ret = unsafe { status.u.nothing_errno }; - wasi_try_mem_ok!(status_ptr.write( - &view, + move |ctx: FunctionEnvMut<'_, WasiEnv>, status: JoinStatusResult| { + let mut ret = Errno::Success; + + let view = unsafe { ctx.data().memory_view(&ctx) }; + let status = match status { + JoinStatusResult::Nothing => JoinStatus { + tag: JoinStatusType::Nothing, + u: JoinStatusUnion { nothing: 0 }, + }, + JoinStatusResult::ExitNormal(pid, exit_code) => { + let option_pid = OptionPid { + tag: OptionTag::Some, + pid: pid.raw() as Pid, + }; + pid_ptr.write(&view, option_pid).ok(); + JoinStatus { - tag: JoinStatusType::Nothing, + tag: JoinStatusType::ExitNormal, u: JoinStatusUnion { - nothing_errno: Errno::Success + exit_normal: exit_code.into(), }, } - )); - Ok(ret) - } else { - Ok(Errno::Success) - } + } + JoinStatusResult::Err(err) => { + ret = err; + JoinStatus { + tag: JoinStatusType::Nothing, + u: JoinStatusUnion { nothing: 0 }, + } + } + }; + wasi_try_mem_ok!(status_ptr.write(&view, status)); + Ok(ret) } }; // If we were just restored the stack then we were woken after a deep sleep // and the return calues are already set - if handle_rewind::(&mut ctx) { - let ret = ret_result(ctx); + if let Some(status) = unsafe { handle_rewind::(&mut ctx) } { + let ret = ret_result(ctx, status); tracing::trace!("rewound join ret={:?}", ret); return ret; } let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let option_pid = wasi_try_mem_ok!(pid_ptr.read(&memory)); let option_pid = match option_pid.tag { OptionTag::None => None, @@ -72,9 +95,7 @@ pub fn proc_join( &memory, JoinStatus { tag: JoinStatusType::Nothing, - u: JoinStatusUnion { - nothing_errno: Errno::Success - }, + u: JoinStatusUnion { nothing: 0 }, } )); @@ -87,61 +108,30 @@ pub fn proc_join( // We wait for any process to exit (if it takes too long // then we go into a deep sleep) - let res = __asyncify_with_deep_sleep_ext::( + let res = __asyncify_with_deep_sleep::( ctx, - None, Duration::from_millis(50), - async move { process.join_any_child().await }, - move |memory, store, res| { - let child_exit = res.unwrap_or_else(Err); - - let memory = memory.view(store); + async move { + let child_exit = process.join_any_child().await; match child_exit { Ok(Some((pid, exit_code))) => { + tracing::trace!(%pid, %exit_code, "triggered child join"); trace!(ret_id = pid.raw(), exit_code = exit_code.raw()); - - let option_pid = OptionPid { - tag: OptionTag::Some, - pid: pid.raw() as Pid, - }; - pid_ptr.write(&memory, option_pid).ok(); - - let status = JoinStatus { - tag: JoinStatusType::ExitNormal, - u: JoinStatusUnion { - exit_normal: exit_code.into(), - }, - }; - status_ptr - .write(&memory, status) - .map_err(mem_error_to_wasi)?; + JoinStatusResult::ExitNormal(pid, exit_code) } Ok(None) => { - let status = JoinStatus { - tag: JoinStatusType::Nothing, - u: JoinStatusUnion { - nothing_errno: Errno::Child, - }, - }; - status_ptr - .write(&memory, status) - .map_err(mem_error_to_wasi)?; + tracing::trace!("triggered child join (no child)"); + JoinStatusResult::Err(Errno::Child) } Err(err) => { - let status = JoinStatus { - tag: JoinStatusType::Nothing, - u: JoinStatusUnion { nothing_errno: err }, - }; - status_ptr - .write(&memory, status) - .map_err(mem_error_to_wasi)?; + tracing::trace!(%err, "error triggered on child join"); + JoinStatusResult::Err(err) } } - Ok(()) }, )?; return match res { - AsyncifyAction::Finish(ctx) => ret_result(ctx), + AsyncifyAction::Finish(ctx, result) => ret_result(ctx, result), AsyncifyAction::Unwind => Ok(Errno::Success), }; } @@ -183,51 +173,18 @@ pub fn proc_join( // Wait for the process to finish let process2 = process.clone(); - let res = __asyncify_with_deep_sleep_ext::( - ctx, - None, - Duration::from_millis(50), - async move { process.join().await.unwrap_or_else(|_| Errno::Child.into()) }, - move |memory, store, res| { - let exit_code = res.unwrap_or_else(ExitCode::Errno); - - trace!(ret_id = pid.raw(), exit_code = exit_code.raw()); - { - let mut inner = process2.inner.write().unwrap(); - inner.children.retain(|a| a.pid != pid); - } - - let memory = memory.view(store); - let status = JoinStatus { - tag: JoinStatusType::ExitNormal, - u: JoinStatusUnion { - exit_normal: exit_code.into(), - }, - }; - status_ptr - .write(&memory, status) - .map_err(mem_error_to_wasi) - .map_err(ExitCode::Errno)?; - Ok(()) - }, - )?; + let res = + __asyncify_with_deep_sleep::(ctx, Duration::from_millis(50), async move { + let exit_code = process.join().await.unwrap_or_else(|_| Errno::Child.into()); + tracing::trace!(%exit_code, "triggered child join"); + JoinStatusResult::ExitNormal(pid, exit_code) + })?; return match res { - AsyncifyAction::Finish(ctx) => ret_result(ctx), + AsyncifyAction::Finish(ctx, result) => ret_result(ctx, result), AsyncifyAction::Unwind => Ok(Errno::Success), }; } trace!(ret_id = pid.raw(), "status=nothing"); - - let env = ctx.data(); - let memory = env.memory_view(&ctx); - - let status = JoinStatus { - tag: JoinStatusType::Nothing, - u: JoinStatusUnion { - nothing_errno: Errno::Success, - }, - }; - wasi_try_mem_ok!(status_ptr.write(&memory, status)); - ret_result(ctx) + ret_result(ctx, JoinStatusResult::Nothing) } diff --git a/lib/wasi/src/syscalls/wasix/proc_parent.rs b/lib/wasi/src/syscalls/wasix/proc_parent.rs index afb3b01cf1d..f1efee72731 100644 --- a/lib/wasi/src/syscalls/wasix/proc_parent.rs +++ b/lib/wasi/src/syscalls/wasix/proc_parent.rs @@ -12,12 +12,12 @@ pub fn proc_parent( let env = ctx.data(); let pid: WasiProcessId = pid.into(); if pid == env.process.pid() { - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; Span::current().record("parent", env.process.ppid().raw()); wasi_try_mem!(ret_parent.write(&memory, env.process.ppid().raw() as Pid)); Errno::Success } else if let Some(process) = env.control_plane.get_process(pid) { - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; Span::current().record("parent", process.pid().raw()); wasi_try_mem!(ret_parent.write(&memory, process.pid().raw() as Pid)); Errno::Success diff --git a/lib/wasi/src/syscalls/wasix/proc_spawn.rs b/lib/wasi/src/syscalls/wasix/proc_spawn.rs index 38fd653ccac..e77064a1dfb 100644 --- a/lib/wasi/src/syscalls/wasix/proc_spawn.rs +++ b/lib/wasi/src/syscalls/wasix/proc_spawn.rs @@ -41,7 +41,7 @@ pub fn proc_spawn( ) -> Result { let env = ctx.data(); let control_plane = &env.control_plane; - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let name = unsafe { get_input_str_bus_ok!(&memory, name, name_len) }; let args = unsafe { get_input_str_bus_ok!(&memory, args, args_len) }; let preopen = unsafe { get_input_str_bus_ok!(&memory, preopen, preopen_len) }; @@ -85,7 +85,7 @@ pub fn proc_spawn( }; let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem_bus_ok!(ret_handles.write(&memory, handles)); Ok(BusErrno::Success) } @@ -145,7 +145,7 @@ pub fn proc_spawn_internal( // Replace the STDIO let (stdin, stdout, stderr) = { let (_, child_state, child_inodes) = - child_env.get_memory_and_wasi_state_and_inodes(&new_store, 0); + unsafe { child_env.get_memory_and_wasi_state_and_inodes(&new_store, 0) }; let mut conv_stdio_mode = |mode: WasiStdioMode, fd: WasiFd| -> Result { match mode { WasiStdioMode::Piped => { @@ -246,7 +246,7 @@ pub fn proc_spawn_internal( inner.children.push(child_process); } let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let handles = BusHandles { bid: child_pid.raw(), diff --git a/lib/wasi/src/syscalls/wasix/resolve.rs b/lib/wasi/src/syscalls/wasix/resolve.rs index 498e107fba3..775e78c198c 100644 --- a/lib/wasi/src/syscalls/wasix/resolve.rs +++ b/lib/wasi/src/syscalls/wasix/resolve.rs @@ -32,7 +32,7 @@ pub fn resolve( let naddrs: usize = wasi_try_ok!(naddrs.try_into().map_err(|_| Errno::Inval)); let mut env = ctx.data(); let host_str = { - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; unsafe { get_input_str_ok!(&memory, host, host_len) } }; Span::current().record("host", host_str.as_str()); @@ -49,7 +49,7 @@ pub fn resolve( env = ctx.data(); let mut idx = 0; - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let addrs = wasi_try_mem_ok!(addrs.slice(&memory, wasi_try_ok!(to_offset::(naddrs)))); for found_ip in found_ips.iter().take(naddrs) { crate::net::write_ip(&memory, addrs.index(idx).as_ptr::(), *found_ip); diff --git a/lib/wasi/src/syscalls/wasix/sock_accept.rs b/lib/wasi/src/syscalls/wasix/sock_accept.rs index 9858ef8cfb7..7d76306643e 100644 --- a/lib/wasi/src/syscalls/wasix/sock_accept.rs +++ b/lib/wasi/src/syscalls/wasix/sock_accept.rs @@ -40,7 +40,7 @@ pub fn sock_accept( )); let env = ctx.data(); - let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let kind = Kind::Socket { socket: InodeSocket::new(InodeSocketKind::TcpStream { diff --git a/lib/wasi/src/syscalls/wasix/sock_addr_local.rs b/lib/wasi/src/syscalls/wasix/sock_addr_local.rs index 0272b255d39..ac329bfd50c 100644 --- a/lib/wasi/src/syscalls/wasix/sock_addr_local.rs +++ b/lib/wasi/src/syscalls/wasix/sock_addr_local.rs @@ -27,7 +27,7 @@ pub fn sock_addr_local( Span::current().record("addr", &format!("{:?}", addr)); - let memory = ctx.data().memory_view(&ctx); + let memory = unsafe { ctx.data().memory_view(&ctx) }; wasi_try!(crate::net::write_ip_port( &memory, ret_addr, diff --git a/lib/wasi/src/syscalls/wasix/sock_addr_peer.rs b/lib/wasi/src/syscalls/wasix/sock_addr_peer.rs index c2b498ad776..c49aea0d072 100644 --- a/lib/wasi/src/syscalls/wasix/sock_addr_peer.rs +++ b/lib/wasi/src/syscalls/wasix/sock_addr_peer.rs @@ -27,7 +27,7 @@ pub fn sock_addr_peer( Span::current().record("addr", &format!("{:?}", addr)); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try!(crate::net::write_ip_port( &memory, ro_addr, diff --git a/lib/wasi/src/syscalls/wasix/sock_bind.rs b/lib/wasi/src/syscalls/wasix/sock_bind.rs index 21d0c324fc9..e8c187dd58f 100644 --- a/lib/wasi/src/syscalls/wasix/sock_bind.rs +++ b/lib/wasi/src/syscalls/wasix/sock_bind.rs @@ -16,7 +16,7 @@ pub fn sock_bind( addr: WasmPtr<__wasi_addr_port_t, M>, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let addr = wasi_try!(crate::net::read_ip_port(&memory, addr)); let addr = SocketAddr::new(addr.0, addr.1); Span::current().record("addr", &format!("{:?}", addr)); diff --git a/lib/wasi/src/syscalls/wasix/sock_connect.rs b/lib/wasi/src/syscalls/wasix/sock_connect.rs index 6eb8b3bb42a..c9f00cc8e19 100644 --- a/lib/wasi/src/syscalls/wasix/sock_connect.rs +++ b/lib/wasi/src/syscalls/wasix/sock_connect.rs @@ -21,7 +21,7 @@ pub fn sock_connect( ) -> Errno { let env = ctx.data(); let net = env.net().clone(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let addr = wasi_try!(crate::net::read_ip_port(&memory, addr)); let addr = SocketAddr::new(addr.0, addr.1); Span::current().record("addr", &format!("{:?}", addr)); diff --git a/lib/wasi/src/syscalls/wasix/sock_get_opt_flag.rs b/lib/wasi/src/syscalls/wasix/sock_get_opt_flag.rs index 3849a280915..54083606e32 100644 --- a/lib/wasi/src/syscalls/wasix/sock_get_opt_flag.rs +++ b/lib/wasi/src/syscalls/wasix/sock_get_opt_flag.rs @@ -25,7 +25,7 @@ pub fn sock_get_opt_flag( )); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let flag = match flag { false => Bool::False, true => Bool::True, diff --git a/lib/wasi/src/syscalls/wasix/sock_get_opt_size.rs b/lib/wasi/src/syscalls/wasix/sock_get_opt_size.rs index 361bf2158db..cedb2cdf56c 100644 --- a/lib/wasi/src/syscalls/wasix/sock_get_opt_size.rs +++ b/lib/wasi/src/syscalls/wasix/sock_get_opt_size.rs @@ -32,7 +32,7 @@ pub fn sock_get_opt_size( )); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem!(ret_size.write(&memory, size)); Errno::Success diff --git a/lib/wasi/src/syscalls/wasix/sock_get_opt_time.rs b/lib/wasi/src/syscalls/wasix/sock_get_opt_time.rs index 9f706540560..02e8386ad01 100644 --- a/lib/wasi/src/syscalls/wasix/sock_get_opt_time.rs +++ b/lib/wasi/src/syscalls/wasix/sock_get_opt_time.rs @@ -32,7 +32,7 @@ pub fn sock_get_opt_time( )); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let time = match time { None => OptionTimestamp { diff --git a/lib/wasi/src/syscalls/wasix/sock_join_multicast_v4.rs b/lib/wasi/src/syscalls/wasix/sock_join_multicast_v4.rs index 158ea2cfc75..e2c0d73351f 100644 --- a/lib/wasi/src/syscalls/wasix/sock_join_multicast_v4.rs +++ b/lib/wasi/src/syscalls/wasix/sock_join_multicast_v4.rs @@ -17,7 +17,7 @@ pub fn sock_join_multicast_v4( iface: WasmPtr<__wasi_addr_ip4_t, M>, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let multiaddr = wasi_try!(crate::net::read_ip_v4(&memory, multiaddr)); let iface = wasi_try!(crate::net::read_ip_v4(&memory, iface)); wasi_try!(__sock_actor_mut( diff --git a/lib/wasi/src/syscalls/wasix/sock_join_multicast_v6.rs b/lib/wasi/src/syscalls/wasix/sock_join_multicast_v6.rs index 44cf50ca52b..53d0417420f 100644 --- a/lib/wasi/src/syscalls/wasix/sock_join_multicast_v6.rs +++ b/lib/wasi/src/syscalls/wasix/sock_join_multicast_v6.rs @@ -17,7 +17,7 @@ pub fn sock_join_multicast_v6( iface: u32, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let multiaddr = wasi_try!(crate::net::read_ip_v6(&memory, multiaddr)); wasi_try!(__sock_actor_mut( &mut ctx, diff --git a/lib/wasi/src/syscalls/wasix/sock_leave_multicast_v4.rs b/lib/wasi/src/syscalls/wasix/sock_leave_multicast_v4.rs index 4597748520c..f96526c5670 100644 --- a/lib/wasi/src/syscalls/wasix/sock_leave_multicast_v4.rs +++ b/lib/wasi/src/syscalls/wasix/sock_leave_multicast_v4.rs @@ -17,7 +17,7 @@ pub fn sock_leave_multicast_v4( iface: WasmPtr<__wasi_addr_ip4_t, M>, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let multiaddr = wasi_try!(crate::net::read_ip_v4(&memory, multiaddr)); let iface = wasi_try!(crate::net::read_ip_v4(&memory, iface)); wasi_try!(__sock_actor_mut( diff --git a/lib/wasi/src/syscalls/wasix/sock_leave_multicast_v6.rs b/lib/wasi/src/syscalls/wasix/sock_leave_multicast_v6.rs index b958ee1597a..7d990c7829a 100644 --- a/lib/wasi/src/syscalls/wasix/sock_leave_multicast_v6.rs +++ b/lib/wasi/src/syscalls/wasix/sock_leave_multicast_v6.rs @@ -17,7 +17,7 @@ pub fn sock_leave_multicast_v6( iface: u32, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let multiaddr = wasi_try!(crate::net::read_ip_v6(&memory, multiaddr)); wasi_try!(__sock_actor_mut( &mut ctx, diff --git a/lib/wasi/src/syscalls/wasix/sock_open.rs b/lib/wasi/src/syscalls/wasix/sock_open.rs index 9013aaa582e..c43688bc07b 100644 --- a/lib/wasi/src/syscalls/wasix/sock_open.rs +++ b/lib/wasi/src/syscalls/wasix/sock_open.rs @@ -29,7 +29,7 @@ pub fn sock_open( ro_sock: WasmPtr, ) -> Errno { let env = ctx.data(); - let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); + let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) }; let kind = match ty { Socktype::Stream | Socktype::Dgram => Kind::Socket { diff --git a/lib/wasi/src/syscalls/wasix/sock_recv.rs b/lib/wasi/src/syscalls/wasix/sock_recv.rs index bb75faf1dd8..e6c55d07a79 100644 --- a/lib/wasi/src/syscalls/wasix/sock_recv.rs +++ b/lib/wasi/src/syscalls/wasix/sock_recv.rs @@ -59,7 +59,7 @@ pub fn sock_recv( Span::current().record("nread", bytes_read); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| Errno::Overflow)); wasi_try_mem_ok!(ro_flags.write(&memory, 0)); @@ -93,7 +93,7 @@ fn sock_recv_internal( wasi_try_ok_ok!(WasiEnv::process_signals_and_exit(ctx)?); let mut env = ctx.data(); - let memory = env.memory_view(ctx); + let memory = unsafe { env.memory_view(ctx) }; let data = wasi_try_ok_ok!(__sock_asyncify( env, diff --git a/lib/wasi/src/syscalls/wasix/sock_recv_from.rs b/lib/wasi/src/syscalls/wasix/sock_recv_from.rs index 2314428ce94..c853b97f329 100644 --- a/lib/wasi/src/syscalls/wasix/sock_recv_from.rs +++ b/lib/wasi/src/syscalls/wasix/sock_recv_from.rs @@ -30,7 +30,7 @@ pub fn sock_recv_from( wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); let mut env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let iovs_arr = wasi_try_mem_ok!(ri_data.slice(&memory, ri_data_len)); let max_size = { diff --git a/lib/wasi/src/syscalls/wasix/sock_send.rs b/lib/wasi/src/syscalls/wasix/sock_send.rs index c802e090e14..e45ec0387b8 100644 --- a/lib/wasi/src/syscalls/wasix/sock_send.rs +++ b/lib/wasi/src/syscalls/wasix/sock_send.rs @@ -26,7 +26,7 @@ pub fn sock_send( ret_data_len: WasmPtr, ) -> Result { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let runtime = env.runtime.clone(); let res = { @@ -79,7 +79,7 @@ pub fn sock_send( }; Span::current().record("nsent", bytes_written); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow)); wasi_try_mem_ok!(ret_data_len.write(&memory, bytes_written)); diff --git a/lib/wasi/src/syscalls/wasix/sock_send_file.rs b/lib/wasi/src/syscalls/wasix/sock_send_file.rs index 3acc59b9136..35545d2ae6c 100644 --- a/lib/wasi/src/syscalls/wasix/sock_send_file.rs +++ b/lib/wasi/src/syscalls/wasix/sock_send_file.rs @@ -188,7 +188,7 @@ pub fn sock_send_file( } Span::current().record("nsent", total_written); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem_ok!(ret_sent.write(&memory, total_written as Filesize)); Ok(Errno::Success) diff --git a/lib/wasi/src/syscalls/wasix/sock_send_to.rs b/lib/wasi/src/syscalls/wasix/sock_send_to.rs index 004dd56d29e..bd86102d82c 100644 --- a/lib/wasi/src/syscalls/wasix/sock_send_to.rs +++ b/lib/wasi/src/syscalls/wasix/sock_send_to.rs @@ -26,11 +26,11 @@ pub fn sock_send_to( ret_data_len: WasmPtr, ) -> Result { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let iovs_arr = wasi_try_mem_ok!(si_data.slice(&memory, si_data_len)); let (addr_ip, addr_port) = { - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_ok!(read_ip_port(&memory, addr)) }; let addr = SocketAddr::new(addr_ip, addr_port); @@ -73,7 +73,7 @@ pub fn sock_send_to( }; Span::current().record("nsent", bytes_written); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| Errno::Overflow)); wasi_try_mem_ok!(ret_data_len.write(&memory, bytes_written)); diff --git a/lib/wasi/src/syscalls/wasix/sock_set_opt_time.rs b/lib/wasi/src/syscalls/wasix/sock_set_opt_time.rs index 52365506745..49e9c037987 100644 --- a/lib/wasi/src/syscalls/wasix/sock_set_opt_time.rs +++ b/lib/wasi/src/syscalls/wasix/sock_set_opt_time.rs @@ -17,7 +17,7 @@ pub fn sock_set_opt_time( time: WasmPtr, ) -> Errno { let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let time = wasi_try_mem!(time.read(&memory)); let time = match time.tag { OptionTag::None => None, diff --git a/lib/wasi/src/syscalls/wasix/sock_status.rs b/lib/wasi/src/syscalls/wasix/sock_status.rs index 5f24d6120e1..81a7b960927 100644 --- a/lib/wasi/src/syscalls/wasix/sock_status.rs +++ b/lib/wasi/src/syscalls/wasix/sock_status.rs @@ -26,7 +26,7 @@ pub fn sock_status( Span::current().record("status", &format!("{:?}", status)); let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem!(ret_status.write(&memory, status)); Errno::Success } diff --git a/lib/wasi/src/syscalls/wasix/stack_checkpoint.rs b/lib/wasi/src/syscalls/wasix/stack_checkpoint.rs index 85023fe30cf..250d191117b 100644 --- a/lib/wasi/src/syscalls/wasix/stack_checkpoint.rs +++ b/lib/wasi/src/syscalls/wasix/stack_checkpoint.rs @@ -11,15 +11,11 @@ pub fn stack_checkpoint( ret_val: WasmPtr, ) -> Result { // If we were just restored then we need to return the value instead - if handle_rewind::(&mut ctx) { + if let Some(val) = unsafe { handle_rewind::(&mut ctx) } { let env = ctx.data(); - let memory = env.memory_view(&ctx); - let ret_val = wasi_try_mem_ok!(ret_val.read(&memory)); - if ret_val == 0 { - trace!("execution resumed",); - } else { - trace!("restored - (ret={})", ret_val); - } + let memory = unsafe { env.memory_view(&ctx) }; + wasi_try_mem_ok!(ret_val.write(&memory, val)); + trace!("restored - (ret={})", val); return Ok(Errno::Success); } trace!("capturing",); @@ -30,7 +26,7 @@ pub fn stack_checkpoint( // indicate we are a normal function call that has not yet // been restored let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem_ok!(ret_val.write(&memory, 0)); // Pass some offsets to the unwind function @@ -124,7 +120,7 @@ pub fn stack_checkpoint( // Save the stack snapshot let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let snapshot_ptr: WasmPtr = WasmPtr::new(snapshot_offset); if let Err(err) = snapshot_ptr.write(&memory, snapshot) { warn!("could not save stack snapshot - {}", err); @@ -134,11 +130,12 @@ pub fn stack_checkpoint( // Rewind the stack and carry on let pid = ctx.data().pid(); let tid = ctx.data().tid(); - match rewind::( + match rewind::( ctx, memory_stack_corrected.freeze(), rewind_stack.freeze(), store_data, + 0 as Longsize, ) { Errno::Success => OnCalledAction::InvokeAgain, err => { diff --git a/lib/wasi/src/syscalls/wasix/stack_restore.rs b/lib/wasi/src/syscalls/wasix/stack_restore.rs index 66c7ea753d8..aae443f43b5 100644 --- a/lib/wasi/src/syscalls/wasix/stack_restore.rs +++ b/lib/wasi/src/syscalls/wasix/stack_restore.rs @@ -16,7 +16,7 @@ pub fn stack_restore( ) -> Result<(), WasiError> { // Read the snapshot from the stack let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let snapshot = match snapshot_ptr.read(&memory) { Ok(a) => { trace!("with_ret={}, hash={}, user={}", val, a.hash, a.user); @@ -36,63 +36,13 @@ pub fn stack_restore( env.thread.get_snapshot(snapshot.hash) { let env = ctx.data(); - let memory = env.memory_view(&ctx); - - // If the return value offset is within the memory stack then we need - // to update it here rather than in the real memory - let val_bytes = val.to_ne_bytes(); - let ret_val_offset = snapshot.user; - if ret_val_offset >= env.layout.stack_lower - && (ret_val_offset + val_bytes.len() as u64) <= env.layout.stack_upper - { - // Make sure its within the "active" part of the memory stack - let offset = env.layout.stack_upper - ret_val_offset; - let end = offset + (val_bytes.len() as u64); - if end as usize > memory_stack.len() { - warn!( - "snapshot stack restore failed - the return value is outside of the active part of the memory stack ({} vs {}) - {} - {}", - offset, - memory_stack.len(), - ret_val_offset, - end - ); - return OnCalledAction::Trap(Box::new(WasiError::Exit( - Errno::Memviolation.into(), - ))); - } else { - // Update the memory stack with the new return value - let pstart = memory_stack.len() - offset as usize; - let pend = pstart + val_bytes.len(); - let pbytes = &mut memory_stack[pstart..pend]; - pbytes.clone_from_slice(&val_bytes); - } - } else { - let err = snapshot - .user - .try_into() - .map_err(|_| Errno::Overflow) - .map(|a| WasmPtr::::new(a)) - .map(|a| { - a.write(&memory, val) - .map(|_| Errno::Success) - .map_err(mem_error_to_wasi) - .unwrap_or_else(|e| e) - }) - .unwrap_or_else(|a| a); - if err != Errno::Success { - warn!( - "snapshot stack restore failed - the return value can not be written too - {}", - err - ); - return OnCalledAction::Trap(Box::new(WasiError::Exit(err.into()))); - } - } + let memory = unsafe { env.memory_view(&ctx) }; // Rewind the stack - after this point we must immediately return // so that the execution can end here and continue elsewhere. let pid = ctx.data().pid(); let tid = ctx.data().tid(); - match rewind::(ctx, memory_stack.freeze(), rewind_stack, store_data) { + match rewind::(ctx, memory_stack.freeze(), rewind_stack, store_data, val) { Errno::Success => OnCalledAction::InvokeAgain, err => { warn!("failed to rewind the stack - errno={}", err); diff --git a/lib/wasi/src/syscalls/wasix/thread_id.rs b/lib/wasi/src/syscalls/wasix/thread_id.rs index 85193c20e67..a8d8de9f6fd 100644 --- a/lib/wasi/src/syscalls/wasix/thread_id.rs +++ b/lib/wasi/src/syscalls/wasix/thread_id.rs @@ -12,7 +12,7 @@ pub fn thread_id( let env = ctx.data(); let tid: Tid = env.thread.tid().into(); Span::current().record("tid", tid); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem!(ret_tid.write(&memory, tid)); Errno::Success } diff --git a/lib/wasi/src/syscalls/wasix/thread_join.rs b/lib/wasi/src/syscalls/wasix/thread_join.rs index 327601ce45c..264e6050aad 100644 --- a/lib/wasi/src/syscalls/wasix/thread_join.rs +++ b/lib/wasi/src/syscalls/wasix/thread_join.rs @@ -8,13 +8,13 @@ use crate::syscalls::*; /// ## Parameters /// /// * `tid` - Handle of the thread to wait on -#[instrument(level = "debug", skip_all, fields(%join_tid), ret, err)] +//#[instrument(level = "debug", skip_all, fields(%join_tid), ret, err)] pub fn thread_join( mut ctx: FunctionEnvMut<'_, WasiEnv>, join_tid: Tid, ) -> Result { wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); - if handle_rewind::(&mut ctx) { + if let Some(_child_exit_code) = unsafe { handle_rewind::(&mut ctx) } { return Ok(Errno::Success); } @@ -22,11 +22,8 @@ pub fn thread_join( let tid: WasiThreadId = join_tid.into(); let other_thread = env.process.get_thread(&tid); if let Some(other_thread) = other_thread { - let res = __asyncify_with_deep_sleep_ext::( - ctx, - None, - Duration::from_millis(50), - async move { + let res = + __asyncify_with_deep_sleep::(ctx, Duration::from_millis(50), async move { other_thread .join() .await @@ -35,9 +32,8 @@ pub fn thread_join( .unwrap_or(ExitCode::Errno(Errno::Unknown)) }) .unwrap_or_else(|a| a) - }, - |_, _, _| Ok(()), - )?; + .raw() + })?; Ok(Errno::Success) } else { Ok(Errno::Success) diff --git a/lib/wasi/src/syscalls/wasix/thread_local_create.rs b/lib/wasi/src/syscalls/wasix/thread_local_create.rs index 5a4ae21175e..f862bef0a58 100644 --- a/lib/wasi/src/syscalls/wasix/thread_local_create.rs +++ b/lib/wasi/src/syscalls/wasix/thread_local_create.rs @@ -26,7 +26,7 @@ pub fn thread_local_create( key }; - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem!(ret_key.write(&memory, key)); Errno::Success } diff --git a/lib/wasi/src/syscalls/wasix/thread_local_destroy.rs b/lib/wasi/src/syscalls/wasix/thread_local_destroy.rs index 3aa5a868756..165a8e6795e 100644 --- a/lib/wasi/src/syscalls/wasix/thread_local_destroy.rs +++ b/lib/wasi/src/syscalls/wasix/thread_local_destroy.rs @@ -25,8 +25,10 @@ pub fn thread_local_destroy(mut ctx: FunctionEnvMut<'_, WasiEnv>, key: TlKey) -> if let Some(user_data) = inner.thread_local_user_data.remove(&key) { drop(inner); - if let Some(thread_local_destroy) = - ctx.data().inner().thread_local_destroy.as_ref().cloned() + if let Some(thread_local_destroy) = unsafe { ctx.data().inner() } + .thread_local_destroy + .as_ref() + .cloned() { for val in data { let user_data_low: u32 = (user_data & 0xFFFFFFFF) as u32; diff --git a/lib/wasi/src/syscalls/wasix/thread_local_get.rs b/lib/wasi/src/syscalls/wasix/thread_local_get.rs index 30be3f5822b..2aeb204c1c3 100644 --- a/lib/wasi/src/syscalls/wasix/thread_local_get.rs +++ b/lib/wasi/src/syscalls/wasix/thread_local_get.rs @@ -23,7 +23,7 @@ pub fn thread_local_get( let val = val.unwrap_or_default(); Span::current().record("val", val); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem!(ret_val.write(&memory, val)); Errno::Success } diff --git a/lib/wasi/src/syscalls/wasix/thread_parallelism.rs b/lib/wasi/src/syscalls/wasix/thread_parallelism.rs index 3f6b65605f3..c8c97587e46 100644 --- a/lib/wasi/src/syscalls/wasix/thread_parallelism.rs +++ b/lib/wasi/src/syscalls/wasix/thread_parallelism.rs @@ -16,7 +16,7 @@ pub fn thread_parallelism( })); Span::current().record("parallelism", parallelism); let parallelism: M::Offset = wasi_try!(parallelism.try_into().map_err(|_| Errno::Overflow)); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem!(ret_parallelism.write(&memory, parallelism)); Errno::Success } diff --git a/lib/wasi/src/syscalls/wasix/thread_sleep.rs b/lib/wasi/src/syscalls/wasix/thread_sleep.rs index 19cf8240186..9035e2cf777 100644 --- a/lib/wasi/src/syscalls/wasix/thread_sleep.rs +++ b/lib/wasi/src/syscalls/wasix/thread_sleep.rs @@ -20,7 +20,7 @@ pub(crate) fn thread_sleep_internal( duration: Timestamp, ) -> Result { wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?); - if handle_rewind::(&mut ctx) { + if let Some(()) = unsafe { handle_rewind::(&mut ctx) } { return Ok(Errno::Success); } @@ -34,21 +34,9 @@ pub(crate) fn thread_sleep_internal( if duration > 0 { let duration = Duration::from_nanos(duration as u64); let tasks = env.tasks().clone(); - - __asyncify_with_deep_sleep_ext::( - ctx, - Some(duration), - Duration::from_millis(50), - async move { - // using an infinite async sleep here means we don't have to write the same event - // handling loop code for signals and timeouts - InfiniteSleep::default().await; - unreachable!( - "the timeout or signals will wake up this thread even though it waits forever" - ) - }, - |_, _, _| Ok(()), - )?; + __asyncify_with_deep_sleep::(ctx, Duration::from_millis(50), async move { + tasks.sleep_now(duration).await; + })?; } Ok(Errno::Success) } diff --git a/lib/wasi/src/syscalls/wasix/thread_spawn.rs b/lib/wasi/src/syscalls/wasix/thread_spawn.rs index 2c0acb5e53d..c5f371b92d4 100644 --- a/lib/wasi/src/syscalls/wasix/thread_spawn.rs +++ b/lib/wasi/src/syscalls/wasix/thread_spawn.rs @@ -1,3 +1,5 @@ +use std::f32::consts::E; + use super::*; use crate::{ capture_snapshot, @@ -23,7 +25,7 @@ use wasmer_wasix_types::wasi::ThreadStart; /// /// Returns the thread index of the newly created thread /// (indices always start from the same value as `pid` and increments in steps) -#[instrument(level = "debug", skip_all, ret)] +//#[instrument(level = "debug", skip_all, ret)] pub fn thread_spawn( mut ctx: FunctionEnvMut<'_, WasiEnv>, start_ptr: WasmPtr, M>, @@ -33,7 +35,7 @@ pub fn thread_spawn( let tid = wasi_try!(thread_spawn_internal(&mut ctx, start_ptr)); // Success - let memory = ctx.data().memory_view(&ctx); + let memory = unsafe { ctx.data().memory_view(&ctx) }; wasi_try_mem!(ret_tid.write(&memory, tid)); Errno::Success } @@ -44,13 +46,13 @@ pub(crate) fn thread_spawn_internal( ) -> Result { // Now we use the environment and memory references let env = ctx.data(); - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let runtime = env.runtime.clone(); let tasks = env.tasks().clone(); let start_ptr_offset = start_ptr.offset(); // We extract the memory which will be passed to the thread - let thread_memory = env.memory_clone(); + let thread_memory = unsafe { env.inner() }.memory_clone(); // Read the properties about the stack which we will use for asyncify let layout = { @@ -61,8 +63,6 @@ pub(crate) fn thread_spawn_internal( let tls_base: u64 = start.tls_base.try_into().map_err(|_| Errno::Overflow)?; let stack_lower = stack_upper - stack_size; - tracing::trace!(%stack_upper, %stack_lower, %stack_size, %guard_size, %tls_base); - WasiMemoryLayout { stack_upper, stack_lower, @@ -70,6 +70,7 @@ pub(crate) fn thread_spawn_internal( stack_size, } }; + tracing::trace!("spawn with layout {:?}", layout); // Create the handle that represents this thread let mut thread_handle = match env.process.new_thread() { @@ -98,7 +99,7 @@ pub(crate) fn thread_spawn_internal( thread_env.enable_deep_sleep = if cfg!(feature = "js") { false } else { - env.capable_of_deep_sleep() + unsafe { env.capable_of_deep_sleep() } }; // This next function gets a context for the local thread and then @@ -113,11 +114,11 @@ pub(crate) fn thread_spawn_internal( // If the process does not export a thread spawn function then obviously // we can't spawn a background thread - if env.inner().thread_spawn.is_none() { + if unsafe { env.inner() }.thread_spawn.is_none() { warn!("thread failed - the program does not export a `wasi_thread_start` function"); return Err(Errno::Notcapable); } - let thread_module = env.inner().module_clone(); + let thread_module = unsafe { env.inner() }.module_clone(); let snapshot = capture_snapshot(&mut ctx.as_store_mut()); let spawn_type = crate::runtime::SpawnMemoryType::ShareMemory(thread_memory, ctx.as_store_ref()); @@ -145,7 +146,7 @@ fn call_module( mut store: Store, start_ptr_offset: M::Offset, thread_handle: Arc, - rewind_state: Option<(RewindState, Result<(), Errno>)>, + rewind_state: Option<(RewindState, Bytes)>, ) -> Result { let env = ctx.data(&store); let tasks = env.tasks().clone(); @@ -154,7 +155,10 @@ fn call_module( let call_module_internal = move |env: &WasiFunctionEnv, store: &mut Store| { // We either call the reactor callback or the thread spawn callback //trace!("threading: invoking thread callback (reactor={})", reactor); - let spawn = env.data(&store).inner().thread_spawn.clone().unwrap(); + let spawn = unsafe { env.data(&store).inner() } + .thread_spawn + .clone() + .unwrap(); let tid = env.data(&store).tid(); let call_ret = spawn.call( store, @@ -198,15 +202,13 @@ fn call_module( }; // If we need to rewind then do so - if let Some((mut rewind_state, trigger_res)) = rewind_state { - if let Err(exit_code) = rewind_state.rewinding_finish::(&ctx, &mut store, trigger_res) { - return Err(exit_code.into()); - } - let res = rewind::( + if let Some((rewind_state, rewind_result)) = rewind_state { + let res = rewind_ext::( ctx.env.clone().into_mut(&mut store), rewind_state.memory_stack, rewind_state.rewind_stack, rewind_state.store_data, + rewind_result, ); if res != Errno::Success { return Err(res); @@ -241,7 +243,9 @@ fn call_module( }; /// Spawns the WASM process after a trigger - tasks.resume_wasm_after_poller(Box::new(respawn), ctx, store, deep.trigger); + unsafe { + tasks.resume_wasm_after_poller(Box::new(respawn), ctx, store, deep.trigger) + }; Err(Errno::Unknown) } } diff --git a/lib/wasi/src/syscalls/wasix/tty_get.rs b/lib/wasi/src/syscalls/wasix/tty_get.rs index cec02059b00..937917a5afe 100644 --- a/lib/wasi/src/syscalls/wasix/tty_get.rs +++ b/lib/wasi/src/syscalls/wasix/tty_get.rs @@ -30,7 +30,7 @@ pub fn tty_get( line_buffered: state.line_buffered, }; - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; wasi_try_mem!(tty_state.write(&memory, state)); Errno::Success diff --git a/lib/wasi/src/syscalls/wasix/tty_set.rs b/lib/wasi/src/syscalls/wasix/tty_set.rs index 1a56ceecd24..0f46e1e25ab 100644 --- a/lib/wasi/src/syscalls/wasix/tty_set.rs +++ b/lib/wasi/src/syscalls/wasix/tty_set.rs @@ -15,7 +15,7 @@ pub fn tty_set( return Errno::Notsup; }; - let memory = env.memory_view(&ctx); + let memory = unsafe { env.memory_view(&ctx) }; let state = wasi_try_mem!(tty_state.read(&memory)); let echo = state.echo; let line_buffered = state.line_buffered;