1#![allow(
2 unused,
3 clippy::too_many_arguments,
4 clippy::cognitive_complexity,
5 clippy::result_large_err
6)]
7
8pub mod types {
9 pub use wasmer_wasix_types::{types::*, wasi};
10}
11
12#[cfg(any(
13 target_os = "freebsd",
14 target_os = "linux",
15 target_os = "android",
16 target_vendor = "apple"
17))]
18pub mod unix;
19#[cfg(target_family = "wasm")]
20pub mod wasm;
21#[cfg(target_os = "windows")]
22pub mod windows;
23
24pub mod journal;
25pub mod wasi;
26pub mod wasix;
27
28use bytes::{Buf, BufMut};
29use futures::{
30 Future,
31 future::{BoxFuture, LocalBoxFuture},
32};
33use tracing::instrument;
34pub use wasi::*;
35pub use wasix::*;
36use wasmer_journal::SnapshotTrigger;
37use wasmer_wasix_types::wasix::ThreadStartType;
38
39pub mod legacy;
40
41pub(crate) use std::{
42 borrow::{Borrow, Cow},
43 cell::RefCell,
44 collections::{HashMap, HashSet, hash_map::Entry},
45 convert::{Infallible, TryInto},
46 io::{self, Read, Seek, Write},
47 mem::transmute,
48 net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
49 num::NonZeroU64,
50 ops::{Deref, DerefMut},
51 path::Path,
52 pin::Pin,
53 sync::{
54 Arc, Condvar, Mutex,
55 atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering},
56 mpsc,
57 },
58 task::{Context, Poll},
59 thread::LocalKey,
60 time::Duration,
61};
62use std::{io::IoSlice, marker::PhantomData, mem::MaybeUninit, task::Waker, time::Instant};
63
64pub(crate) use bytes::{Bytes, BytesMut};
65pub(crate) use cooked_waker::IntoWaker;
66pub use journal::*;
67pub(crate) use sha2::Sha256;
68pub(crate) use tracing::{debug, error, trace, warn};
69#[cfg(any(
70 target_os = "freebsd",
71 target_os = "linux",
72 target_os = "android",
73 target_vendor = "apple"
74))]
75pub use unix::*;
76#[cfg(target_family = "wasm")]
77pub use wasm::*;
78
79pub(crate) use virtual_fs::{
80 AsyncSeekExt, AsyncWriteExt, DuplexPipe, FileSystem, FsError, VirtualFile,
81};
82pub(crate) use virtual_net::StreamSecurity;
83pub(crate) use wasmer::{
84 AsStoreMut, AsStoreRef, Extern, Function, FunctionEnv, FunctionEnvMut, Global, Instance,
85 Memory, Memory32, Memory64, MemoryAccessError, MemoryError, MemorySize, MemoryView, Module,
86 OnCalledAction, Pages, RuntimeError, Store, TypedFunction, Value, WasmPtr, WasmSlice,
87};
88pub(crate) use wasmer_wasix_types::{asyncify::__wasi_asyncify_t, wasi::EventUnion};
89#[cfg(target_os = "windows")]
90pub use windows::*;
91
92pub(crate) use self::types::{
93 wasi::{
94 Addressfamily, Advice, Clockid, Dircookie, Dirent, DlFlags, DlHandle, Errno, Event,
95 EventFdReadwrite, Eventrwflags, Eventtype, ExitCode, Fd as WasiFd, Fdflags, Fdflagsext,
96 Fdstat, Filesize, Filestat, Filetype, Fstflags, Linkcount, Longsize, OptionFd, Pid,
97 Prestat, ProcSpawnFdOp, Rights, SignalDisposition, Snapshot0Clockid, Sockoption,
98 Sockstatus, Socktype, StackSnapshot, StdioMode as WasiStdioMode, Streamsecurity,
99 Subscription, SubscriptionFsReadwrite, Tid, Timestamp, TlKey, TlUser, TlVal, Tty, Whence,
100 },
101 *,
102};
103use self::{
104 state::{WasiInstanceGuardMemory, conv_env_vars},
105 utils::WasiDummyWaker,
106};
107pub(crate) use crate::os::task::{
108 process::{WasiProcessId, WasiProcessWait},
109 thread::{WasiThread, WasiThreadId},
110};
111use crate::{
112 DeepSleepWork, RewindPostProcess, RewindState, RewindStateOption, SpawnError, WasiInodes,
113 WasiResult, WasiRuntimeError,
114 fs::{
115 Fd, FdInner, InodeVal, Kind, MAX_SYMLINKS, fs_error_into_wasi_err,
116 virtual_file_type_to_wasi_file_type,
117 },
118 journal::{DynJournal, DynReadableJournal, DynWritableJournal, JournalEffector},
119 os::task::{
120 process::{MaybeCheckpointResult, WasiProcessCheckpoint},
121 thread::{RewindResult, RewindResultType},
122 },
123 runtime::task_manager::InlineWaker,
124 utils::store::StoreSnapshot,
125};
126pub(crate) use crate::{
127 Runtime, VirtualTaskManager, WasiEnv, WasiError, WasiFunctionEnv, WasiModuleTreeHandles,
128 WasiVFork,
129 bin_factory::spawn_exec_module,
130 import_object_for_all_wasi_versions, mem_error_to_wasi,
131 net::{
132 read_ip_port,
133 socket::{InodeHttpSocketType, InodeSocket, InodeSocketKind},
134 write_ip_port,
135 },
136 runtime::SpawnType,
137 state::{
138 self, InodeGuard, InodeWeakGuard, PollEvent, PollEventBuilder, WasiFutex, WasiState,
139 iterate_poll_events,
140 },
141 utils::{self, map_io_err},
142};
143pub(crate) use crate::{net::net_error_into_wasi_err, utils::WasiParkingLot};
144
145pub(crate) fn to_offset<M: MemorySize>(offset: usize) -> Result<M::Offset, Errno> {
146 let ret: M::Offset = offset.try_into().map_err(|_| Errno::Inval)?;
147 Ok(ret)
148}
149
150pub(crate) fn from_offset<M: MemorySize>(offset: M::Offset) -> Result<usize, Errno> {
151 let ret: usize = offset.try_into().map_err(|_| Errno::Inval)?;
152 Ok(ret)
153}
154
155pub(crate) fn write_bytes_inner<T: Write, M: MemorySize>(
156 mut write_loc: T,
157 memory: &MemoryView,
158 iovs_arr_cell: WasmSlice<__wasi_ciovec_t<M>>,
159) -> Result<usize, Errno> {
160 let mut bytes_written = 0usize;
161 for iov in iovs_arr_cell.iter() {
162 let iov_inner = iov.read().map_err(mem_error_to_wasi)?;
163 let bytes = WasmPtr::<u8, M>::new(iov_inner.buf)
164 .slice(memory, iov_inner.buf_len)
165 .map_err(mem_error_to_wasi)?;
166 let bytes = bytes.read_to_vec().map_err(mem_error_to_wasi)?;
167 write_loc.write_all(&bytes).map_err(map_io_err)?;
168
169 bytes_written += from_offset::<M>(iov_inner.buf_len)?;
170 }
171 Ok(bytes_written)
172}
173
174pub(crate) fn write_bytes<T: Write, M: MemorySize>(
175 mut write_loc: T,
176 memory: &MemoryView,
177 iovs_arr: WasmSlice<__wasi_ciovec_t<M>>,
178) -> Result<usize, Errno> {
179 let result = write_bytes_inner::<_, M>(&mut write_loc, memory, iovs_arr);
180 write_loc.flush();
181 result
182}
183
184pub(crate) fn copy_from_slice<M: MemorySize>(
185 mut read_loc: &[u8],
186 memory: &MemoryView,
187 iovs_arr: WasmSlice<__wasi_iovec_t<M>>,
188) -> Result<usize, Errno> {
189 let mut bytes_read = 0usize;
190
191 let iovs_arr = iovs_arr.access().map_err(mem_error_to_wasi)?;
192 for iovs in iovs_arr.iter() {
193 let mut buf = WasmPtr::<u8, M>::new(iovs.buf)
194 .slice(memory, iovs.buf_len)
195 .map_err(mem_error_to_wasi)?
196 .access()
197 .map_err(mem_error_to_wasi)?;
198
199 let to_read = from_offset::<M>(iovs.buf_len)?;
200 let to_read = to_read.min(read_loc.len());
201 if to_read == 0 {
202 break;
203 }
204 let (left, right) = read_loc.split_at(to_read);
205 let amt = buf.copy_from_slice_min(left);
206 if amt != to_read {
207 return Ok(bytes_read + amt);
208 }
209
210 read_loc = right;
211 bytes_read += to_read;
212 }
213 Ok(bytes_read)
214}
215
216pub(crate) fn read_bytes<T: Read, M: MemorySize>(
217 mut reader: T,
218 memory: &MemoryView,
219 iovs_arr: WasmSlice<__wasi_iovec_t<M>>,
220) -> Result<usize, Errno> {
221 let mut bytes_read = 0usize;
222
223 let iovs_arr = iovs_arr.access().map_err(mem_error_to_wasi)?;
224 for iovs in iovs_arr.iter() {
225 let mut buf = WasmPtr::<u8, M>::new(iovs.buf)
226 .slice(memory, iovs.buf_len)
227 .map_err(mem_error_to_wasi)?
228 .access()
229 .map_err(mem_error_to_wasi)?;
230
231 let to_read = buf.len();
232 let has_read = reader.read(buf.as_mut()).map_err(map_io_err)?;
233
234 bytes_read += has_read;
235 if has_read != to_read {
236 return Ok(bytes_read);
237 }
238 }
239 Ok(bytes_read)
240}
241
242#[allow(clippy::await_holding_lock)]
245pub unsafe fn stderr_write<'a>(
246 ctx: &FunctionEnvMut<'_, WasiEnv>,
247 buf: &[u8],
248) -> LocalBoxFuture<'a, Result<(), Errno>> {
249 let env = ctx.data();
250 let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(ctx, 0) };
251
252 let buf = buf.to_vec();
253 let mut stderr = WasiInodes::stderr_mut(&state.fs.fd_map).map_err(fs_error_into_wasi_err);
254 Box::pin(async move { stderr?.write_all(&buf).await.map_err(map_io_err) })
255}
256
257fn block_on_with_timeout<T, Fut>(
258 tasks: &Arc<dyn VirtualTaskManager>,
259 timeout: Option<Duration>,
260 work: Fut,
261) -> WasiResult<T>
262where
263 Fut: Future<Output = WasiResult<T>>,
264{
265 let mut nonblocking = false;
266 if timeout == Some(Duration::ZERO) {
267 nonblocking = true;
268 }
269 let timeout = async {
270 if let Some(timeout) = timeout {
271 if !nonblocking {
272 tasks.sleep_now(timeout).await
273 } else {
274 InfiniteSleep::default().await
275 }
276 } else {
277 InfiniteSleep::default().await
278 }
279 };
280
281 let work = async move {
282 tokio::select! {
283 res = work => res,
285 _ = timeout => Ok(Err(Errno::Timedout)),
287 }
288 };
289
290 if nonblocking {
292 let waker = WasiDummyWaker.into_waker();
293 let mut cx = Context::from_waker(&waker);
294 let mut pinned_work = Box::pin(work);
295 if let Poll::Ready(res) = pinned_work.as_mut().poll(&mut cx) {
296 return res;
297 }
298 return Ok(Err(Errno::Again));
299 }
300
301 InlineWaker::block_on(work)
303}
304
305pub(crate) fn __asyncify<T, Fut>(
310 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
311 timeout: Option<Duration>,
312 work: Fut,
313) -> WasiResult<T>
314where
315 T: 'static,
316 Fut: std::future::Future<Output = Result<T, Errno>>,
317{
318 let mut env = ctx.data();
319
320 if let Some(exit_code) = env.should_exit() {
322 return Err(WasiError::Exit(exit_code));
323 }
324
325 struct SignalPoller<'a, 'b, Fut, T>
327 where
328 Fut: Future<Output = Result<T, Errno>>,
329 {
330 ctx: &'a mut FunctionEnvMut<'b, WasiEnv>,
331 pinned_work: Pin<Box<Fut>>,
332 }
333 impl<Fut, T> Future for SignalPoller<'_, '_, Fut, T>
334 where
335 Fut: Future<Output = Result<T, Errno>>,
336 {
337 type Output = Result<Fut::Output, WasiError>;
338 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
339 if let Poll::Ready(res) = Pin::new(&mut self.pinned_work).poll(cx) {
340 return Poll::Ready(Ok(res));
341 }
342 if let Some(signals) = self.ctx.data().thread.pop_signals_or_subscribe(cx.waker()) {
343 if let Err(err) = WasiEnv::process_signals_internal(self.ctx, signals) {
344 return Poll::Ready(Err(err));
345 }
346 return Poll::Ready(Ok(Err(Errno::Intr)));
347 }
348 Poll::Pending
349 }
350 }
351
352 let mut pinned_work = Box::pin(work);
354 let tasks = env.tasks().clone();
355 let poller = SignalPoller { ctx, pinned_work };
356 block_on_with_timeout(&tasks, timeout, poller)
357}
358
359pub type AsyncifyFuture = dyn Future<Output = Bytes> + Send + Sync + 'static;
363
364struct AsyncifyPoller<'a, 'b, 'c, T, Fut>
366where
367 Fut: Future<Output = T> + Send + Sync + 'static,
368{
369 ctx: &'b mut FunctionEnvMut<'c, WasiEnv>,
370 work: &'a mut Pin<Box<Fut>>,
371}
372impl<T, Fut> Future for AsyncifyPoller<'_, '_, '_, T, Fut>
373where
374 Fut: Future<Output = T> + Send + Sync + 'static,
375{
376 type Output = Result<T, WasiError>;
377
378 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
379 if let Poll::Ready(res) = self.work.as_mut().poll(cx) {
380 return Poll::Ready(Ok(res));
381 }
382
383 WasiEnv::do_pending_link_operations(self.ctx, false);
384
385 let env = self.ctx.data();
386 if let Some(forced_exit) = env.thread.try_join() {
387 return Poll::Ready(Err(WasiError::Exit(forced_exit.unwrap_or_else(|err| {
388 tracing::debug!("exit runtime error - {}", err);
389 Errno::Child.into()
390 }))));
391 }
392 if env.thread.has_signals_or_subscribe(cx.waker()) {
393 let has_exit = {
394 let signals = env.thread.signals().lock().unwrap();
395 signals
396 .0
397 .iter()
398 .filter_map(|sig| {
399 if *sig == Signal::Sigint
400 || *sig == Signal::Sigquit
401 || *sig == Signal::Sigkill
402 || *sig == Signal::Sigabrt
403 {
404 Some(env.thread.set_or_get_exit_code_for_signal(*sig))
405 } else {
406 None
407 }
408 })
409 .next()
410 };
411
412 return match WasiEnv::process_signals_and_exit(self.ctx) {
413 Ok(Ok(_)) => {
414 if let Some(exit_code) = has_exit {
415 Poll::Ready(Err(WasiError::Exit(exit_code)))
416 } else {
417 self.ctx.data().thread.signals_subscribe(cx.waker());
419 Poll::Pending
420 }
421 }
422 Ok(Err(err)) => Poll::Ready(Err(WasiError::Exit(ExitCode::from(err)))),
423 Err(err) => Poll::Ready(Err(err)),
424 };
425 }
426 Poll::Pending
427 }
428}
429
430pub enum AsyncifyAction<'a, R> {
431 Finish(FunctionEnvMut<'a, WasiEnv>, R),
434 Unwind,
437}
438
439pub(crate) fn maybe_backoff<M: MemorySize>(
450 mut ctx: FunctionEnvMut<'_, WasiEnv>,
451) -> Result<Result<FunctionEnvMut<'_, WasiEnv>, Errno>, WasiError> {
452 let env = ctx.data();
453
454 if env.enable_exponential_cpu_backoff.is_none() {
457 return Ok(Ok(ctx));
458 }
459
460 if let Some(backoff) = env.process.acquire_cpu_backoff_token(env.tasks()) {
462 tracing::trace!("exponential CPU backoff {:?}", backoff.backoff_time());
463 if let AsyncifyAction::Finish(mut ctx, _) =
464 __asyncify_with_deep_sleep::<M, _, _>(ctx, backoff)?
465 {
466 Ok(Ok(ctx))
467 } else {
468 Ok(Err(Errno::Success))
469 }
470 } else {
471 Ok(Ok(ctx))
472 }
473}
474
475pub(crate) fn __asyncify_with_deep_sleep<M: MemorySize, T, Fut>(
485 mut ctx: FunctionEnvMut<'_, WasiEnv>,
486 work: Fut,
487) -> Result<AsyncifyAction<'_, T>, WasiError>
488where
489 T: serde::Serialize + serde::de::DeserializeOwned,
490 Fut: Future<Output = T> + Send + Sync + 'static,
491{
492 let deep_sleep_time = match ctx.data().enable_journal {
494 true => Duration::from_micros(100),
495 false => Duration::from_millis(50),
496 };
497
498 let mut trigger = Box::pin(work);
500
501 let tasks = ctx.data().tasks().clone();
503 let work = async move {
504 let env = ctx.data();
505
506 let tasks_for_deep_sleep = if env.enable_deep_sleep && env.inner().linker().is_none() {
510 Some(env.tasks().clone())
511 } else {
512 None
513 };
514
515 let deep_sleep_wait = async {
516 if let Some(tasks) = tasks_for_deep_sleep {
517 tasks.sleep_now(deep_sleep_time).await
518 } else {
519 InfiniteSleep::default().await
520 }
521 };
522
523 Ok(tokio::select! {
524 res = AsyncifyPoller {
526 ctx: &mut ctx,
527 work: &mut trigger,
528 } => {
529 let result = res?;
530 AsyncifyAction::Finish(ctx, result)
531 },
532 _ = deep_sleep_wait => {
534 let pid = ctx.data().pid();
535 let tid = ctx.data().tid();
536
537 let thread = ctx.data().thread.clone();
540 thread.set_deep_sleeping(true);
541 ctx.data().process.inner.1.notify_one();
542
543 tracing::trace!(%pid, %tid, "thread entering deep sleep");
544 deep_sleep::<M>(ctx, Box::pin(async move {
545 let result = trigger.await;
548 tracing::trace!(%pid, %tid, "thread leaving deep sleep");
549 thread.set_deep_sleeping(false);
550 bincode::serialize(&result).unwrap().into()
551 }))?;
552 AsyncifyAction::Unwind
553 },
554 })
555 };
556
557 InlineWaker::block_on(work)
560}
561
562pub(crate) fn __asyncify_light<T, Fut>(
567 env: &WasiEnv,
568 _timeout: Option<Duration>,
569 work: Fut,
570) -> WasiResult<T>
571where
572 T: 'static,
573 Fut: Future<Output = Result<T, Errno>>,
574{
575 let snapshot_wait = wait_for_snapshot(env);
576
577 Ok(InlineWaker::block_on(work))
580}
581
582#[derive(Default)]
586pub struct InfiniteSleep {}
587impl std::future::Future for InfiniteSleep {
588 type Output = ();
589 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
590 Poll::Pending
591 }
592}
593
594pub(crate) fn __sock_asyncify<T, F, Fut>(
597 env: &WasiEnv,
598 sock: WasiFd,
599 rights: Rights,
600 actor: F,
601) -> Result<T, Errno>
602where
603 F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Fut,
604 Fut: std::future::Future<Output = Result<T, Errno>>,
605{
606 let fd_entry = env.state.fs.get_fd(sock)?;
607 if !rights.is_empty() && !fd_entry.inner.rights.contains(rights) {
608 return Err(Errno::Access);
609 }
610
611 let mut work = {
612 let inode = fd_entry.inode.clone();
613 let tasks = env.tasks().clone();
614 let mut guard = inode.write();
615 match guard.deref_mut() {
616 Kind::Socket { socket } => {
617 let socket = socket.clone();
619 drop(guard);
620
621 actor(socket, fd_entry)
623 }
624 _ => {
625 return Err(Errno::Notsock);
626 }
627 }
628 };
629
630 InlineWaker::block_on(work)
633}
634
635pub(crate) fn __sock_asyncify_mut<T, F, Fut>(
638 ctx: &'_ mut FunctionEnvMut<'_, WasiEnv>,
639 sock: WasiFd,
640 rights: Rights,
641 actor: F,
642) -> Result<T, Errno>
643where
644 F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Fut,
645 Fut: std::future::Future<Output = Result<T, Errno>>,
646{
647 let env = ctx.data();
648 let tasks = env.tasks().clone();
649
650 let fd_entry = env.state.fs.get_fd(sock)?;
651 if !rights.is_empty() && !fd_entry.inner.rights.contains(rights) {
652 return Err(Errno::Access);
653 }
654
655 let inode = fd_entry.inode.clone();
656 let mut guard = inode.write();
657 match guard.deref_mut() {
658 Kind::Socket { socket } => {
659 let socket = socket.clone();
661 drop(guard);
662
663 let mut work = actor(socket, fd_entry);
665
666 InlineWaker::block_on(work)
669 }
670 _ => Err(Errno::Notsock),
671 }
672}
673
674pub(crate) fn __sock_actor<T, F>(
677 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
678 sock: WasiFd,
679 rights: Rights,
680 actor: F,
681) -> Result<T, Errno>
682where
683 T: 'static,
684 F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Result<T, Errno>,
685{
686 let env = ctx.data();
687 let tasks = env.tasks().clone();
688
689 let fd_entry = env.state.fs.get_fd(sock)?;
690 if !rights.is_empty() && !fd_entry.inner.rights.contains(rights) {
691 return Err(Errno::Access);
692 }
693
694 let inode = fd_entry.inode.clone();
695
696 let tasks = env.tasks().clone();
697 let mut guard = inode.write();
698 match guard.deref_mut() {
699 Kind::Socket { socket } => {
700 let socket = socket.clone();
702 drop(guard);
703
704 actor(socket, fd_entry)
706 }
707 _ => Err(Errno::Notsock),
708 }
709}
710
711pub(crate) fn __sock_actor_mut<T, F>(
714 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
715 sock: WasiFd,
716 rights: Rights,
717 actor: F,
718) -> Result<T, Errno>
719where
720 T: 'static,
721 F: FnOnce(crate::net::socket::InodeSocket, Fd) -> Result<T, Errno>,
722{
723 let env = ctx.data();
724 let tasks = env.tasks().clone();
725
726 let fd_entry = env.state.fs.get_fd(sock)?;
727 if !rights.is_empty() && !fd_entry.inner.rights.contains(rights) {
728 return Err(Errno::Access);
729 }
730
731 let inode = fd_entry.inode.clone();
732 let mut guard = inode.write();
733 match guard.deref_mut() {
734 Kind::Socket { socket } => {
735 let socket = socket.clone();
737 drop(guard);
738
739 actor(socket, fd_entry)
741 }
742 _ => Err(Errno::Notsock),
743 }
744}
745
746pub(crate) fn __sock_upgrade<'a, F, Fut>(
750 ctx: &'a mut FunctionEnvMut<'_, WasiEnv>,
751 sock: WasiFd,
752 rights: Rights,
753 actor: F,
754) -> Result<(), Errno>
755where
756 F: FnOnce(crate::net::socket::InodeSocket, Fdflags) -> Fut,
757 Fut: std::future::Future<Output = Result<Option<crate::net::socket::InodeSocket>, Errno>> + 'a,
758{
759 let env = ctx.data();
760 let fd_entry = env.state.fs.get_fd(sock)?;
761 if !rights.is_empty() && !fd_entry.inner.rights.contains(rights) {
762 tracing::warn!(
763 "wasi[{}:{}]::sock_upgrade(fd={}, rights={:?}) - failed - no access rights to upgrade",
764 ctx.data().pid(),
765 ctx.data().tid(),
766 sock,
767 rights
768 );
769 return Err(Errno::Access);
770 }
771
772 let tasks = env.tasks().clone();
773 {
774 let inode = fd_entry.inode;
775 let mut guard = inode.write();
776 match guard.deref_mut() {
777 Kind::Socket { socket } => {
778 let socket = socket.clone();
779 drop(guard);
780
781 let work = actor(socket, fd_entry.inner.flags);
783
784 let res = InlineWaker::block_on(work);
786 let new_socket = res?;
787
788 if let Some(mut new_socket) = new_socket {
789 let mut guard = inode.write();
790 match guard.deref_mut() {
791 Kind::Socket { socket, .. } => {
792 std::mem::swap(socket, &mut new_socket);
793 }
794 _ => {
795 tracing::warn!(
796 "wasi[{}:{}]::sock_upgrade(fd={}, rights={:?}) - failed - not a socket",
797 ctx.data().pid(),
798 ctx.data().tid(),
799 sock,
800 rights
801 );
802 return Err(Errno::Notsock);
803 }
804 }
805 }
806 }
807 _ => {
808 tracing::warn!(
809 "wasi[{}:{}]::sock_upgrade(fd={}, rights={:?}) - failed - not a socket",
810 ctx.data().pid(),
811 ctx.data().tid(),
812 sock,
813 rights
814 );
815 return Err(Errno::Notsock);
816 }
817 }
818 }
819
820 Ok(())
821}
822
823#[must_use]
824pub(crate) fn write_buffer_array<M: MemorySize>(
825 memory: &MemoryView,
826 from: &[Vec<u8>],
827 ptr_buffer: WasmPtr<WasmPtr<u8, M>, M>,
828 buffer: WasmPtr<u8, M>,
829) -> Errno {
830 let ptrs = wasi_try_mem!(ptr_buffer.slice(memory, wasi_try!(to_offset::<M>(from.len()))));
831
832 let mut current_buffer_offset = 0usize;
833 for ((i, sub_buffer), ptr) in from.iter().enumerate().zip(ptrs.iter()) {
834 let mut buf_offset = buffer.offset();
835 buf_offset += wasi_try!(to_offset::<M>(current_buffer_offset));
836 let new_ptr = WasmPtr::new(buf_offset);
837 wasi_try_mem!(ptr.write(new_ptr));
838
839 let data =
840 wasi_try_mem!(new_ptr.slice(memory, wasi_try!(to_offset::<M>(sub_buffer.len()))));
841 wasi_try_mem!(data.write_slice(sub_buffer));
842 wasi_try_mem!(
843 wasi_try_mem!(new_ptr.add_offset(wasi_try!(to_offset::<M>(sub_buffer.len()))))
844 .write(memory, 0)
845 );
846
847 current_buffer_offset += sub_buffer.len() + 1;
848 }
849
850 Errno::Success
851}
852
853pub(crate) fn get_current_time_in_nanos() -> Result<Timestamp, Errno> {
854 let now = platform_clock_time_get(Snapshot0Clockid::Monotonic, 1_000_000).unwrap() as u128;
855 Ok(now as Timestamp)
856}
857
858pub(crate) fn get_stack_lower(env: &WasiEnv) -> u64 {
859 env.layout.stack_lower
860}
861
862pub(crate) fn get_stack_upper(env: &WasiEnv) -> u64 {
863 env.layout.stack_upper
864}
865
866pub(crate) unsafe fn get_memory_stack_pointer(
867 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
868) -> Result<u64, String> {
869 let stack_upper = get_stack_upper(ctx.data());
872 let stack_pointer = if let Some(stack_pointer) = ctx
873 .data()
874 .inner()
875 .main_module_instance_handles()
876 .stack_pointer
877 .clone()
878 {
879 match stack_pointer.get(ctx) {
880 Value::I32(a) => a as u64,
881 Value::I64(a) => a as u64,
882 _ => stack_upper,
883 }
884 } else {
885 return Err("failed to save stack: no __stack_pointer global".to_string());
886 };
887 Ok(stack_pointer)
888}
889
890pub(crate) unsafe fn get_memory_stack_offset(
891 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
892) -> Result<u64, String> {
893 let stack_upper = get_stack_upper(ctx.data());
894 let stack_pointer = unsafe { get_memory_stack_pointer(ctx) }?;
895 Ok(stack_upper - stack_pointer)
896}
897
898pub(crate) fn set_memory_stack_offset(
899 env: &WasiEnv,
900 store: &mut impl AsStoreMut,
901 offset: u64,
902) -> Result<(), String> {
903 let stack_upper = get_stack_upper(env);
905 let stack_pointer = stack_upper - offset;
906 if let Some(stack_pointer_ptr) = env
907 .inner()
908 .main_module_instance_handles()
909 .stack_pointer
910 .clone()
911 {
912 match stack_pointer_ptr.get(store) {
913 Value::I32(_) => {
914 stack_pointer_ptr.set(store, Value::I32(stack_pointer as i32));
915 }
916 Value::I64(_) => {
917 stack_pointer_ptr.set(store, Value::I64(stack_pointer as i64));
918 }
919 _ => {
920 return Err(
921 "failed to save stack: __stack_pointer global is of an unknown type"
922 .to_string(),
923 );
924 }
925 }
926 } else {
927 return Err("failed to save stack: no __stack_pointer global".to_string());
928 }
929 Ok(())
930}
931
932#[allow(dead_code)]
933pub(crate) fn get_memory_stack<M: MemorySize>(
934 env: &WasiEnv,
935 store: &mut impl AsStoreMut,
936) -> Result<BytesMut, String> {
937 let stack_base = get_stack_upper(env);
940 let stack_pointer = if let Some(stack_pointer) = env
941 .inner()
942 .main_module_instance_handles()
943 .stack_pointer
944 .clone()
945 {
946 match stack_pointer.get(store) {
947 Value::I32(a) => a as u64,
948 Value::I64(a) => a as u64,
949 _ => stack_base,
950 }
951 } else {
952 return Err("failed to save stack: no __stack_pointer global".to_string());
953 };
954 let memory = env
955 .try_memory_view(store)
956 .ok_or_else(|| "unable to access the memory of the instance".to_string())?;
957 let stack_offset = env.layout.stack_upper - stack_pointer;
958
959 let memory_stack_ptr = WasmPtr::<u8, M>::new(
961 stack_pointer
962 .try_into()
963 .map_err(|err| format!("failed to save stack: stack pointer overflow (stack_pointer={}, stack_lower={}, stack_upper={})", stack_offset, env.layout.stack_lower, env.layout.stack_upper))?,
964 );
965
966 memory_stack_ptr
967 .slice(
968 &memory,
969 stack_offset
970 .try_into()
971 .map_err(|err| format!("failed to save stack: stack pointer overflow (stack_pointer={}, stack_lower={}, stack_upper={})", stack_offset, env.layout.stack_lower, env.layout.stack_upper))?,
972 )
973 .and_then(|memory_stack| memory_stack.read_to_bytes())
974 .map_err(|err| format!("failed to read stack: {err}"))
975}
976
977#[allow(dead_code)]
978pub(crate) fn set_memory_stack<M: MemorySize>(
979 env: &WasiEnv,
980 store: &mut impl AsStoreMut,
981 stack: Bytes,
982) -> Result<(), String> {
983 let stack_upper = get_stack_upper(env);
985 let stack_offset = stack.len() as u64;
986 let stack_pointer = stack_upper - stack_offset;
987 let stack_ptr = WasmPtr::<u8, M>::new(
988 stack_pointer
989 .try_into()
990 .map_err(|_| "failed to restore stack: stack pointer overflow".to_string())?,
991 );
992
993 let memory = env
994 .try_memory_view(store)
995 .ok_or_else(|| "unable to set the stack pointer of the instance".to_string())?;
996 stack_ptr
997 .slice(
998 &memory,
999 stack_offset
1000 .try_into()
1001 .map_err(|_| "failed to restore stack: stack pointer overflow".to_string())?,
1002 )
1003 .and_then(|memory_stack| memory_stack.write_slice(&stack[..]))
1004 .map_err(|err| format!("failed to write stack: {err}"))?;
1005
1006 set_memory_stack_offset(env, store, stack_offset)?;
1008 Ok(())
1009}
1010
1011#[must_use = "you must return the result immediately so the stack can unwind"]
1014pub(crate) fn deep_sleep<M: MemorySize>(
1015 mut ctx: FunctionEnvMut<'_, WasiEnv>,
1016 trigger: Pin<Box<AsyncifyFuture>>,
1017) -> Result<(), WasiError> {
1018 let store_data = crate::utils::store::capture_store_snapshot(&mut ctx.as_store_mut())
1020 .serialize()
1021 .unwrap();
1022 let store_data = Bytes::from(store_data);
1023 let thread_start = ctx.data().thread.thread_start_type();
1024
1025 let tasks = ctx.data().tasks().clone();
1027 let res = unwind::<M, _>(ctx, move |mut ctx, memory_stack, rewind_stack| {
1028 let memory_stack = memory_stack.freeze();
1029 let rewind_stack = rewind_stack.freeze();
1030 let thread_layout = ctx.data().thread.memory_layout().clone();
1031
1032 if ctx.data().enable_journal {
1034 let store_data = crate::utils::store::capture_store_snapshot(&mut ctx.as_store_mut())
1036 .serialize()
1037 .unwrap();
1038 let store_data = Bytes::from(store_data);
1039
1040 tracing::trace!(
1041 "stack snapshot unwind (memory_stack={}, rewind_stack={}, store_data={})",
1042 memory_stack.len(),
1043 rewind_stack.len(),
1044 store_data.len(),
1045 );
1046
1047 #[cfg(feature = "journal")]
1048 {
1049 let tid = ctx.data().thread.tid();
1051 let thread_start = ctx.data().thread.thread_start_type();
1052 if let Err(err) = JournalEffector::save_thread_state::<M>(
1053 &mut ctx,
1054 tid,
1055 memory_stack.clone(),
1056 rewind_stack.clone(),
1057 store_data.clone(),
1058 thread_start,
1059 thread_layout.clone(),
1060 ) {
1061 return wasmer_types::OnCalledAction::Trap(err.into());
1062 }
1063 }
1064
1065 let inner = ctx.data().process.inner.clone();
1068 let is_idle = {
1069 let mut guard = inner.0.lock().unwrap();
1070 guard.threads.values().all(WasiThread::is_deep_sleeping)
1071 };
1072
1073 #[cfg(feature = "journal")]
1077 {
1078 if is_idle && ctx.data_mut().has_snapshot_trigger(SnapshotTrigger::Idle) {
1079 let mut guard = inner.0.lock().unwrap();
1080 if let Err(err) = JournalEffector::save_memory_and_snapshot(
1081 &mut ctx,
1082 &mut guard,
1083 SnapshotTrigger::Idle,
1084 ) {
1085 return wasmer_types::OnCalledAction::Trap(err.into());
1086 }
1087 }
1088 }
1089 }
1090
1091 OnCalledAction::Trap(Box::new(WasiError::DeepSleep(DeepSleepWork {
1093 trigger,
1094 rewind: RewindState {
1095 memory_stack,
1096 rewind_stack,
1097 store_data,
1098 start: thread_start,
1099 layout: thread_layout,
1100 is_64bit: M::is_64bit(),
1101 },
1102 })))
1103 })?;
1104
1105 match res {
1107 Errno::Success => Ok(()),
1108 err => Err(WasiError::Exit(ExitCode::from(err))),
1109 }
1110}
1111
1112#[must_use = "you must return the result immediately so the stack can unwind"]
1113pub fn unwind<M: MemorySize, F>(
1114 mut ctx: FunctionEnvMut<'_, WasiEnv>,
1115 callback: F,
1116) -> Result<Errno, WasiError>
1117where
1118 F: FnOnce(FunctionEnvMut<'_, WasiEnv>, BytesMut, BytesMut) -> OnCalledAction
1119 + Send
1120 + Sync
1121 + 'static,
1122{
1123 let (env, mut store) = ctx.data_and_store_mut();
1126 let memory_stack = match get_memory_stack::<M>(env, &mut store) {
1127 Ok(a) => a,
1128 Err(err) => {
1129 warn!("unable to get the memory stack - {}", err);
1130 return Err(WasiError::Exit(Errno::Unknown.into()));
1131 }
1132 };
1133
1134 let env = ctx.data();
1136 let memory = unsafe { env.memory_view(&ctx) };
1137
1138 let unwind_pointer = env.layout.stack_lower;
1140 let unwind_data_start =
1141 unwind_pointer + (std::mem::size_of::<__wasi_asyncify_t<M::Offset>>() as u64);
1142 let unwind_data = __wasi_asyncify_t::<M::Offset> {
1143 start: wasi_try_ok!(unwind_data_start.try_into().map_err(|_| Errno::Overflow)),
1144 end: wasi_try_ok!(
1145 (env.layout.stack_upper - memory_stack.len() as u64)
1146 .try_into()
1147 .map_err(|_| Errno::Overflow)
1148 ),
1149 };
1150 let unwind_data_ptr: WasmPtr<__wasi_asyncify_t<M::Offset>, M> = WasmPtr::new(wasi_try_ok!(
1151 unwind_pointer.try_into().map_err(|_| Errno::Overflow)
1152 ));
1153 wasi_try_mem_ok!(unwind_data_ptr.write(&memory, unwind_data));
1154
1155 let asyncify_data = wasi_try_ok!(unwind_pointer.try_into().map_err(|_| Errno::Overflow));
1158 if let Some(asyncify_start_unwind) = env
1159 .inner()
1160 .static_module_instance_handles()
1161 .and_then(|handles| handles.asyncify_start_unwind.clone())
1162 {
1163 asyncify_start_unwind.call(&mut ctx, asyncify_data);
1164 } else {
1165 warn!("failed to unwind the stack because the asyncify_start_rewind export is missing");
1166 return Err(WasiError::Exit(Errno::Noexec.into()));
1167 }
1168
1169 let env = ctx.data();
1171 let unwind_stack_begin: u64 = unwind_data.start.into();
1172 let total_stack_space = env.layout.stack_size;
1173 let func = ctx.as_ref();
1174 trace!(
1175 stack_upper = env.layout.stack_upper,
1176 stack_lower = env.layout.stack_lower,
1177 "wasi[{}:{}]::unwinding (used_stack_space={} total_stack_space={})",
1178 ctx.data().pid(),
1179 ctx.data().tid(),
1180 memory_stack.len(),
1181 total_stack_space
1182 );
1183 ctx.as_store_mut().on_called(move |mut store| {
1184 let mut ctx = func.into_mut(&mut store);
1185 let env = ctx.data();
1186 let memory = env
1187 .try_memory_view(&ctx)
1188 .ok_or_else(|| "failed to save stack: stack pointer overflow - unable to access the memory of the instance".to_string())?;
1189
1190 let unwind_data_ptr: WasmPtr<__wasi_asyncify_t<M::Offset>, M> = WasmPtr::new(
1191 unwind_pointer
1192 .try_into()
1193 .map_err(|_| Errno::Overflow)
1194 .unwrap(),
1195 );
1196 let unwind_data_result = unwind_data_ptr.read(&memory).unwrap();
1197 let unwind_stack_finish: u64 = unwind_data_result.start.into();
1198 let unwind_size = unwind_stack_finish - unwind_stack_begin;
1199 trace!(
1200 "wasi[{}:{}]::unwound (memory_stack_size={} unwind_size={})",
1201 ctx.data().pid(),
1202 ctx.data().tid(),
1203 memory_stack.len(),
1204 unwind_size
1205 );
1206
1207 let unwind_stack_ptr = WasmPtr::<u8, M>::new(
1209 unwind_stack_begin
1210 .try_into()
1211 .map_err(|_| "failed to save stack: stack pointer overflow".to_string())?,
1212 );
1213 let unwind_stack = unwind_stack_ptr
1214 .slice(
1215 &memory,
1216 unwind_size
1217 .try_into()
1218 .map_err(|_| "failed to save stack: stack pointer overflow".to_string())?,
1219 )
1220 .and_then(|memory_stack| memory_stack.read_to_bytes())
1221 .map_err(|err| format!("failed to read stack: {err}"))?;
1222
1223 if let Some(asyncify_stop_unwind) = env
1225 .inner()
1226 .static_module_instance_handles()
1227 .and_then(|i| i.asyncify_stop_unwind.clone())
1228 {
1229 asyncify_stop_unwind.call(&mut ctx);
1230 } else {
1231 warn!("failed to unwind the stack because the asyncify_start_rewind export is missing");
1232 return Ok(OnCalledAction::Finish);
1233 }
1234
1235 Ok(callback(ctx, memory_stack, unwind_stack))
1236 });
1237
1238 Ok(Errno::Success)
1240}
1241
1242#[must_use = "the action must be passed to the call loop"]
1244pub fn rewind<M: MemorySize, T>(
1245 mut ctx: FunctionEnvMut<WasiEnv>,
1246 memory_stack: Option<Bytes>,
1247 rewind_stack: Bytes,
1248 store_data: Bytes,
1249 result: T,
1250) -> Errno
1251where
1252 T: serde::Serialize,
1253{
1254 let rewind_result = bincode::serialize(&result).unwrap().into();
1255 rewind_ext::<M>(
1256 &mut ctx,
1257 memory_stack,
1258 rewind_stack,
1259 store_data,
1260 RewindResultType::RewindWithResult(rewind_result),
1261 )
1262}
1263
1264#[instrument(level = "trace", skip_all, fields(rewind_stack_len = rewind_stack.len(), store_data_len = store_data.len()))]
1265#[must_use = "the action must be passed to the call loop"]
1266pub fn rewind_ext<M: MemorySize>(
1267 ctx: &mut FunctionEnvMut<WasiEnv>,
1268 memory_stack: Option<Bytes>,
1269 rewind_stack: Bytes,
1270 store_data: Bytes,
1271 rewind_result: RewindResultType,
1272) -> Errno {
1273 ctx.data_mut().thread.set_rewind(RewindResult {
1275 memory_stack,
1276 rewind_result,
1277 });
1278
1279 let store_snapshot = match StoreSnapshot::deserialize(&store_data[..]) {
1281 Ok(a) => a,
1282 Err(err) => {
1283 warn!("snapshot restore failed - the store snapshot could not be deserialized");
1284 return Errno::Unknown;
1285 }
1286 };
1287 crate::utils::store::restore_store_snapshot(ctx, &store_snapshot);
1288 let env = ctx.data();
1289 let memory = match env.try_memory_view(&ctx) {
1290 Some(v) => v,
1291 None => {
1292 warn!("snapshot restore failed - unable to access the memory of the instance");
1293 return Errno::Unknown;
1294 }
1295 };
1296
1297 let rewind_pointer = env.layout.stack_lower;
1299 let rewind_data_start =
1300 rewind_pointer + (std::mem::size_of::<__wasi_asyncify_t<M::Offset>>() as u64);
1301 let rewind_data_end = rewind_data_start + (rewind_stack.len() as u64);
1302 if rewind_data_end > env.layout.stack_upper {
1303 warn!(
1304 "attempting to rewind a stack bigger than the allocated stack space ({} > {})",
1305 rewind_data_end, env.layout.stack_upper
1306 );
1307 return Errno::Overflow;
1308 }
1309 let rewind_data = __wasi_asyncify_t::<M::Offset> {
1310 start: wasi_try!(rewind_data_end.try_into().map_err(|_| Errno::Overflow)),
1311 end: wasi_try!(
1312 env.layout
1313 .stack_upper
1314 .try_into()
1315 .map_err(|_| Errno::Overflow)
1316 ),
1317 };
1318 let rewind_data_ptr: WasmPtr<__wasi_asyncify_t<M::Offset>, M> = WasmPtr::new(wasi_try!(
1319 rewind_pointer.try_into().map_err(|_| Errno::Overflow)
1320 ));
1321 wasi_try_mem!(rewind_data_ptr.write(&memory, rewind_data));
1322
1323 let rewind_stack_ptr = WasmPtr::<u8, M>::new(wasi_try!(
1325 rewind_data_start.try_into().map_err(|_| Errno::Overflow)
1326 ));
1327 wasi_try_mem!(
1328 rewind_stack_ptr
1329 .slice(
1330 &memory,
1331 wasi_try!(rewind_stack.len().try_into().map_err(|_| Errno::Overflow))
1332 )
1333 .and_then(|stack| { stack.write_slice(&rewind_stack[..]) })
1334 );
1335
1336 let asyncify_data = wasi_try!(rewind_pointer.try_into().map_err(|_| Errno::Overflow));
1338 if let Some(asyncify_start_rewind) = env
1339 .inner()
1340 .static_module_instance_handles()
1341 .and_then(|a| a.asyncify_start_rewind.clone())
1342 {
1343 asyncify_start_rewind.call(ctx, asyncify_data);
1344 } else {
1345 warn!(
1346 "failed to rewind the stack because the asyncify_start_rewind export is missing or inaccessible"
1347 );
1348 return Errno::Noexec;
1349 }
1350
1351 Errno::Success
1352}
1353
1354pub fn rewind_ext2(
1355 ctx: &mut FunctionEnvMut<WasiEnv>,
1356 rewind_state: RewindStateOption,
1357) -> Result<(), ExitCode> {
1358 if let Some((rewind_state, rewind_result)) = rewind_state {
1359 tracing::trace!("Rewinding");
1360 let errno = if rewind_state.is_64bit {
1361 crate::rewind_ext::<wasmer_types::Memory64>(
1362 ctx,
1363 Some(rewind_state.memory_stack),
1364 rewind_state.rewind_stack,
1365 rewind_state.store_data,
1366 rewind_result,
1367 )
1368 } else {
1369 crate::rewind_ext::<wasmer_types::Memory32>(
1370 ctx,
1371 Some(rewind_state.memory_stack),
1372 rewind_state.rewind_stack,
1373 rewind_state.store_data,
1374 rewind_result,
1375 )
1376 };
1377
1378 if errno != Errno::Success {
1379 let exit_code = ExitCode::from(errno);
1380 ctx.data().blocking_on_exit(Some(exit_code));
1381 return Err(exit_code);
1382 }
1383 }
1384
1385 Ok(())
1386}
1387
1388pub fn anyhow_err_to_runtime_err(err: anyhow::Error) -> WasiRuntimeError {
1389 WasiRuntimeError::Runtime(RuntimeError::user(err.into()))
1390}
1391
1392pub(crate) unsafe fn handle_rewind<M: MemorySize, T>(
1393 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1394) -> Option<T>
1395where
1396 T: serde::de::DeserializeOwned,
1397{
1398 unsafe { handle_rewind_ext::<M, T>(ctx, HandleRewindType::ResultDriven) }.flatten()
1399}
1400
1401pub(crate) enum HandleRewindType {
1402 ResultDriven,
1404 ResultLess,
1407}
1408
1409pub(crate) unsafe fn handle_rewind_ext_with_default<M: MemorySize, T>(
1410 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1411 type_: HandleRewindType,
1412) -> Option<T>
1413where
1414 T: serde::de::DeserializeOwned + Default,
1415{
1416 let ret = unsafe { handle_rewind_ext::<M, T>(ctx, type_) };
1417 ret.unwrap_or_default()
1418}
1419
1420pub(crate) unsafe fn handle_rewind_ext<M: MemorySize, T>(
1421 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
1422 type_: HandleRewindType,
1423) -> Option<Option<T>>
1424where
1425 T: serde::de::DeserializeOwned,
1426{
1427 let env = ctx.data();
1428 if !env.thread.has_rewind_of_type(type_) {
1429 return None;
1430 };
1431
1432 let tid = env.tid();
1434 let pid = env.pid();
1435 if let Some(result) = ctx.data_mut().thread.take_rewind() {
1436 let memory_stack = result.memory_stack;
1438
1439 let env = ctx.data();
1441 if let Some(asyncify_stop_rewind) = env
1442 .inner()
1443 .static_module_instance_handles()
1444 .and_then(|handles| handles.asyncify_stop_unwind.clone())
1445 {
1446 asyncify_stop_rewind.call(ctx);
1447 } else {
1448 warn!(
1449 "failed to handle rewind because the asyncify_start_rewind export is missing or inaccessible"
1450 );
1451 return Some(None);
1452 }
1453
1454 let (env, mut store) = ctx.data_and_store_mut();
1456 if let Some(memory_stack) = memory_stack {
1457 set_memory_stack::<M>(env, &mut store, memory_stack);
1458 }
1459
1460 match result.rewind_result {
1461 RewindResultType::RewindRestart => {
1462 tracing::trace!(%pid, %tid, "rewind for syscall restart");
1463 None
1464 }
1465 RewindResultType::RewindWithoutResult => {
1466 tracing::trace!(%pid, %tid, "rewind with no result");
1467 Some(None)
1468 }
1469 RewindResultType::RewindWithResult(rewind_result) => {
1470 tracing::trace!(%pid, %tid, "rewind with result (data={})", rewind_result.len());
1471 let ret = bincode::deserialize(&rewind_result)
1472 .expect("failed to deserialize the rewind result");
1473 Some(Some(ret))
1474 }
1475 }
1476 } else {
1477 tracing::trace!(%pid, %tid, "rewind miss");
1478 Some(None)
1479 }
1480}
1481
1482pub(crate) fn _prepare_wasi(
1484 wasi_env: &mut WasiEnv,
1485 args: Option<Vec<String>>,
1486 envs: Option<Vec<(String, String)>>,
1487 signals: Option<Vec<SignalDisposition>>,
1488) {
1489 if let Some(args) = args {
1491 *wasi_env.state.args.lock().unwrap() = args;
1492 }
1493
1494 if let Some(envs) = envs {
1496 let mut guard = wasi_env.state.envs.lock().unwrap();
1497
1498 let mut existing_envs = guard
1499 .iter()
1500 .map(|b| {
1501 let string = String::from_utf8_lossy(b);
1502 let (key, val) = string.split_once('=').expect("env var is malformed");
1503
1504 (key.to_string(), val.to_string().as_bytes().to_vec())
1505 })
1506 .collect::<Vec<_>>();
1507
1508 for (key, val) in envs {
1509 let val = val.as_bytes().to_vec();
1510 match existing_envs
1511 .iter_mut()
1512 .find(|(existing_key, _)| existing_key == &key)
1513 {
1514 Some((_, existing_val)) => *existing_val = val,
1515 None => existing_envs.push((key, val)),
1516 }
1517 }
1518
1519 let envs = conv_env_vars(existing_envs);
1520
1521 *guard = envs;
1522
1523 drop(guard)
1524 }
1525
1526 if let Some(signals) = signals {
1527 let mut guard = wasi_env.state.signals.lock().unwrap();
1528 for signal in signals {
1529 guard.insert(signal.sig, signal.disp);
1530 }
1531 drop(guard);
1532 }
1533}
1534
1535pub(crate) fn conv_spawn_err_to_errno(err: &SpawnError) -> Errno {
1536 match err {
1537 SpawnError::AccessDenied => Errno::Access,
1538 SpawnError::Unsupported => Errno::Noexec,
1539 _ if err.is_not_found() => Errno::Noent,
1540 _ => Errno::Inval,
1541 }
1542}
1543
1544pub(crate) fn conv_spawn_err_to_exit_code(err: &SpawnError) -> ExitCode {
1545 conv_spawn_err_to_errno(err).into()
1546}