From db55edca8da89f590be32f349873d007030e2996 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Fri, 4 Jul 2025 22:29:15 +0100 Subject: [PATCH 01/18] expose snapshots to the public API Signed-off-by: Jorge Prendes --- src/hyperlight_host/src/mem/mgr.rs | 35 +++++++++++++++---- .../src/mem/shared_mem_snapshot.rs | 10 ++++-- .../src/sandbox/initialized_multi_use.rs | 18 ++++++++++ src/hyperlight_host/src/sandbox/mod.rs | 3 ++ src/hyperlight_host/src/sandbox/snapshot.rs | 8 +++++ 5 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 src/hyperlight_host/src/sandbox/snapshot.rs diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 90cb76573..66d76f701 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -265,10 +265,33 @@ where } } + pub(crate) fn snapshot(&mut self) -> Result { + SharedMemorySnapshot::new(&mut self.shared_mem, self.mapped_rgns) + } + + + /// This function restores a memory snapshot the given snapshot. + /// + /// Returns the number of memory regions mapped into the sandbox + /// that need to be unmapped in order for the restore to be + /// completed. + pub(crate) fn restore_snapshot(&mut self, snapshot: &SharedMemorySnapshot) -> Result { + if self.shared_mem.mem_size() != snapshot.mem_size() { + return Err(new_error!( + "Snapshot size does not match current memory size: {} != {}", + self.shared_mem.raw_mem_size(), + snapshot.mem_size() + )); + } + let old_rgns = self.mapped_rgns; + self.mapped_rgns = snapshot.restore_from_snapshot(&mut self.shared_mem)?; + Ok(old_rgns - self.mapped_rgns) + } + /// this function will create a memory snapshot and push it onto the stack of snapshots /// It should be used when you want to save the state of the memory, for example, when evolving a sandbox to a new state pub(crate) fn push_state(&mut self) -> Result<()> { - let snapshot = SharedMemorySnapshot::new(&mut self.shared_mem, self.mapped_rgns)?; + let snapshot = self.snapshot()?; self.snapshots .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? @@ -285,16 +308,14 @@ where /// that need to be unmapped in order for the restore to be /// completed. pub(crate) fn restore_state_from_last_snapshot(&mut self) -> Result { - let mut snapshots = self + let snapshots = self .snapshots .try_lock() .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?; - let last = snapshots.last_mut(); - if last.is_none() { + let last = snapshots.last(); + let Some(snapshot) = last else { log_then_return!(NoMemorySnapshot); - } - #[allow(clippy::unwrap_used)] // We know that last is not None because we checked it above - let snapshot = last.unwrap(); + }; let old_rgns = self.mapped_rgns; self.mapped_rgns = snapshot.restore_from_snapshot(&mut self.shared_mem)?; Ok(old_rgns - self.mapped_rgns) diff --git a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs index ac2bdc6b5..18bcb43f9 100644 --- a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs +++ b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs @@ -22,7 +22,7 @@ use crate::Result; /// A wrapper around a `SharedMemory` reference and a snapshot /// of the memory therein #[derive(Clone)] -pub(super) struct SharedMemorySnapshot { +pub(crate) struct SharedMemorySnapshot { snapshot: Vec, /// How many non-main-RAM regions were mapped when this snapshot was taken? mapped_rgns: u64, @@ -54,12 +54,18 @@ impl SharedMemorySnapshot { /// into the internally-stored `SharedMemory` #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] pub(super) fn restore_from_snapshot( - &mut self, + &self, shared_mem: &mut S, ) -> Result { shared_mem.with_exclusivity(|e| e.copy_from_slice(self.snapshot.as_slice(), 0))??; Ok(self.mapped_rgns) } + + /// Return the size of the snapshot in bytes. + #[instrument(skip_all, parent = Span::current(), level= "Trace")] + pub(super) fn mem_size(&self) -> usize { + self.snapshot.len() + } } #[cfg(test)] diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index c2959262b..0ae05c29f 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -28,6 +28,7 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{ use tracing::{Span, instrument}; use super::host_funcs::FunctionRegistry; +use super::snapshot::Snapshot; use super::{MemMgrWrapper, WrapperGetter}; use crate::func::call_ctx::MultiUseGuestCallContext; use crate::func::guest_err::check_for_guest_error; @@ -163,6 +164,23 @@ impl MultiUseSandbox { MultiUseGuestCallContext::start(self) } + /// Create a snapshot of the current state of the sandbox's memory. + #[instrument(err(Debug), skip_all, parent = Span::current())] + pub fn snapshot(&mut self) -> Result { + let snapshot = self.mem_mgr.unwrap_mgr_mut().snapshot()?; + Ok(Snapshot { inner: snapshot }) + } + + /// Restore the sandbox's memory to the state captured in the given snapshot. + #[instrument(err(Debug), skip_all, parent = Span::current())] + pub fn restore(&mut self, snapshot: &Snapshot) -> Result<()> { + let rgns_to_unmap = self.mem_mgr + .unwrap_mgr_mut() + .restore_snapshot(&snapshot.inner)?; + unsafe { self.vm.unmap_regions(rgns_to_unmap)? }; + Ok(()) + } + /// Call a guest function by name, with the given return type and arguments. #[instrument(err(Debug), skip(self, args), parent = Span::current())] pub fn call_guest_function_by_name( diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index c6e33c84b..48638a762 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -37,6 +37,9 @@ pub mod uninitialized; /// initialized `Sandbox`es. pub(crate) mod uninitialized_evolve; +/// Representation of a snapshot of a `Sandbox`. +pub mod snapshot; + /// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm mod callable; diff --git a/src/hyperlight_host/src/sandbox/snapshot.rs b/src/hyperlight_host/src/sandbox/snapshot.rs new file mode 100644 index 000000000..76a6da0c5 --- /dev/null +++ b/src/hyperlight_host/src/sandbox/snapshot.rs @@ -0,0 +1,8 @@ +use crate::mem::shared_mem_snapshot::SharedMemorySnapshot; + +/// A snapshot capturing the state of the memory in a `MultiUseSandbox`. +#[derive(Clone)] +pub struct Snapshot { + /// TODO: Use Arc + pub(crate) inner: SharedMemorySnapshot, +} From 14ba90e22babf4d52d328b4e72978be2646c08ac Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Mon, 7 Jul 2025 14:49:37 +0100 Subject: [PATCH 02/18] remove usage of devolve Signed-off-by: Jorge Prendes --- .../src/sandbox/initialized_multi_use.rs | 20 ++++++----- .../src/sandbox_state/transition.rs | 36 ------------------- 2 files changed, 12 insertions(+), 44 deletions(-) diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 0ae05c29f..8040ccbc7 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -425,7 +425,7 @@ mod tests { #[cfg(target_os = "linux")] use crate::mem::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory as _}; use crate::sandbox::{Callable, SandboxConfiguration}; - use crate::sandbox_state::sandbox::{DevolvableSandbox, EvolvableSandbox}; + use crate::sandbox_state::sandbox::EvolvableSandbox; use crate::sandbox_state::transition::{MultiUseContextCallback, Noop}; use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; @@ -469,26 +469,30 @@ mod tests { } /// Tests that evolving from MultiUseSandbox to MultiUseSandbox creates a new state - /// and devolving from MultiUseSandbox to MultiUseSandbox restores the previous state + /// and restoring a snapshot from before evolving restores the previous state #[test] - fn evolve_devolve_handles_state_correctly() { - let sbox1: MultiUseSandbox = { + fn snapshot_evolve_restore_handles_state_correctly() { + let mut sbox: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); u_sbox.evolve(Noop::default()) } .unwrap(); + let snapshot = sbox.snapshot().unwrap(); + let func = Box::new(|call_ctx: &mut MultiUseGuestCallContext| { call_ctx.call::("AddToStatic", 5i32)?; Ok(()) }); let transition_func = MultiUseContextCallback::from(func); - let mut sbox2 = sbox1.evolve(transition_func).unwrap(); - let res: i32 = sbox2.call_guest_function_by_name("GetStatic", ()).unwrap(); + let mut sbox = sbox.evolve(transition_func).unwrap(); + + let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); assert_eq!(res, 5); - let mut sbox3: MultiUseSandbox = sbox2.devolve(Noop::default()).unwrap(); - let res: i32 = sbox3.call_guest_function_by_name("GetStatic", ()).unwrap(); + + sbox.restore(&snapshot).unwrap(); + let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); assert_eq!(res, 0); } diff --git a/src/hyperlight_host/src/sandbox_state/transition.rs b/src/hyperlight_host/src/sandbox_state/transition.rs index 3cd7aaadf..a6f883751 100644 --- a/src/hyperlight_host/src/sandbox_state/transition.rs +++ b/src/hyperlight_host/src/sandbox_state/transition.rs @@ -140,39 +140,3 @@ where } } } -#[cfg(test)] -mod tests { - use super::Noop; - use crate::Result; - use crate::sandbox_state::sandbox::{DevolvableSandbox, EvolvableSandbox, Sandbox}; - - #[derive(Debug, Eq, PartialEq, Clone)] - struct MySandbox1 {} - #[derive(Debug, Eq, PartialEq, Clone)] - struct MySandbox2 {} - - impl Sandbox for MySandbox1 {} - impl Sandbox for MySandbox2 {} - - impl EvolvableSandbox> for MySandbox1 { - fn evolve(self, _: Noop) -> Result { - Ok(MySandbox2 {}) - } - } - - impl DevolvableSandbox> for MySandbox2 { - fn devolve(self, _: Noop) -> Result { - Ok(MySandbox1 {}) - } - } - - #[test] - fn test_evolve_devolve() { - let sbox_1_1 = MySandbox1 {}; - let sbox_2_1 = sbox_1_1.clone().evolve(Noop::default()).unwrap(); - let sbox_1_2 = sbox_2_1.clone().devolve(Noop::default()).unwrap(); - let sbox_2_2 = sbox_1_2.clone().evolve(Noop::default()).unwrap(); - assert_eq!(sbox_1_1, sbox_1_2); - assert_eq!(sbox_2_1, sbox_2_2); - } -} From c4687bbef2ad664de5d08526ab860b8ad49c65b1 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Mon, 7 Jul 2025 14:54:35 +0100 Subject: [PATCH 03/18] remove DevolvableSandbox trait Signed-off-by: Jorge Prendes --- .../src/sandbox/initialized_multi_use.rs | 25 ++----------------- .../src/sandbox_state/sandbox.rs | 13 ++-------- .../src/sandbox_state/transition.rs | 11 ++++---- 3 files changed, 9 insertions(+), 40 deletions(-) diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 8040ccbc7..0a566de56 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -43,8 +43,8 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::maybe_time_and_emit_guest_call; -use crate::sandbox_state::sandbox::{DevolvableSandbox, EvolvableSandbox, Sandbox}; -use crate::sandbox_state::transition::{MultiUseContextCallback, Noop}; +use crate::sandbox_state::sandbox::{EvolvableSandbox, Sandbox}; +use crate::sandbox_state::transition::MultiUseContextCallback; use crate::{HyperlightError, Result, log_then_return}; /// A sandbox that supports being used Multiple times. @@ -360,27 +360,6 @@ impl std::fmt::Debug for MultiUseSandbox { } } -impl DevolvableSandbox> - for MultiUseSandbox -{ - /// Consume `self` and move it back to a `MultiUseSandbox` with previous state. - /// - /// The purpose of this function is to allow multiple states to be associated with a single MultiUseSandbox. - /// - /// An implementation such as HyperlightJs or HyperlightWasm can use this to call guest functions to load JS or WASM code and then evolve the sandbox causing state to be captured. - /// The new MultiUseSandbox can then be used to call guest functions to execute the loaded code. - /// The devolve can be used to return the MultiUseSandbox to the state before the code was loaded. Thus avoiding initialisation overhead - #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn devolve(mut self, _tsn: Noop) -> Result { - let rgns_to_unmap = self - .mem_mgr - .unwrap_mgr_mut() - .pop_and_restore_state_from_snapshot()?; - unsafe { self.vm.unmap_regions(rgns_to_unmap)? }; - Ok(self) - } -} - impl<'a, F> EvolvableSandbox< MultiUseSandbox, diff --git a/src/hyperlight_host/src/sandbox_state/sandbox.rs b/src/hyperlight_host/src/sandbox_state/sandbox.rs index 4f9641af8..b00c490e7 100644 --- a/src/hyperlight_host/src/sandbox_state/sandbox.rs +++ b/src/hyperlight_host/src/sandbox_state/sandbox.rs @@ -30,9 +30,8 @@ use crate::{Result, new_error}; /// into a next state. That "next state" may in turn know how to roll back /// to the root node. /// -/// These transitions are expressed as `EvolvableSandbox` and -/// `DevolvableSandbox` implementations any `Sandbox` implementation can -/// opt into. +/// These transitions are expressed as `EvolvableSandbox` implementations +/// any `Sandbox` implementation can opt into. pub trait Sandbox: Sized + Debug { /// Check to ensure the current stack cookie matches the one that /// was selected when the stack was constructed. @@ -70,11 +69,3 @@ pub trait EvolvableSandbox Result; } - -/// A `Sandbox` that knows how to roll back to a "previous" `Sandbox` -pub trait DevolvableSandbox>: - Sandbox -{ - /// Devolve `Self` to `Prev` providing Metadata. - fn devolve(self, tsn: T) -> Result; -} diff --git a/src/hyperlight_host/src/sandbox_state/transition.rs b/src/hyperlight_host/src/sandbox_state/transition.rs index a6f883751..f4bf9bbfd 100644 --- a/src/hyperlight_host/src/sandbox_state/transition.rs +++ b/src/hyperlight_host/src/sandbox_state/transition.rs @@ -22,9 +22,9 @@ use super::sandbox::Sandbox; use crate::Result; use crate::func::call_ctx::MultiUseGuestCallContext; -/// Metadata about an evolution or devolution. Any `Sandbox` implementation -/// that also implements `EvolvableSandbox` or `DevolvableSandbox` -/// can decide the following things in a type-safe way: +/// Metadata about an evolution. Any `Sandbox` implementation +/// that also implements `EvolvableSandbox` can decide the following +/// things in a type-safe way: /// /// 1. That transition is possible /// 2. That transition requires a specific kind of metadata @@ -40,8 +40,7 @@ use crate::func::call_ctx::MultiUseGuestCallContext; /// ``` /// /// ...then you can define a metadata-free evolve transition between -/// `MySandbox1` and `MySandbox2`, and a devolve transition that requires -/// a callback between `MySandbox2` and `MySandbox` as follows: +/// `MySandbox1` and `MySandbox2` as follows: /// /// ```ignore /// impl EvolvableSandbox< @@ -65,7 +64,7 @@ pub trait TransitionMetadata {} /// Transition metadata that contains and does nothing. `Noop` is a /// placeholder when you want to implement an `EvolvableSandbox` -/// or `DevolvableSandbox` that needs no additional metadata to succeed. +/// that needs no additional metadata to succeed. /// /// Construct one of these by using the `default()` method. pub struct Noop { From 97181fa538e5be4b32bb8235990a010355a1038d Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Mon, 7 Jul 2025 15:05:51 +0100 Subject: [PATCH 04/18] Remove dead code Signed-off-by: Jorge Prendes --- src/hyperlight_host/src/mem/mgr.rs | 15 --------------- .../src/mem/shared_mem_snapshot.rs | 5 +---- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 66d76f701..4eeeda605 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -321,21 +321,6 @@ where Ok(old_rgns - self.mapped_rgns) } - /// this function pops the last snapshot off the stack and restores the memory to the previous state - /// It should be used when you want to restore the state of the memory to a previous state and do not need to retain that state - /// for example when devolving a sandbox to a previous state. - pub(crate) fn pop_and_restore_state_from_snapshot(&mut self) -> Result { - let last = self - .snapshots - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .pop(); - if last.is_none() { - log_then_return!(NoMemorySnapshot); - } - self.restore_state_from_last_snapshot() - } - /// Sets `addr` to the correct offset in the memory referenced by /// `shared_mem` to indicate the address of the outb pointer and context /// for calling outb function diff --git a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs index 18bcb43f9..b7f461716 100644 --- a/src/hyperlight_host/src/mem/shared_mem_snapshot.rs +++ b/src/hyperlight_host/src/mem/shared_mem_snapshot.rs @@ -53,10 +53,7 @@ impl SharedMemorySnapshot { /// Copy the memory from the internally-stored memory snapshot /// into the internally-stored `SharedMemory` #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - pub(super) fn restore_from_snapshot( - &self, - shared_mem: &mut S, - ) -> Result { + pub(super) fn restore_from_snapshot(&self, shared_mem: &mut S) -> Result { shared_mem.with_exclusivity(|e| e.copy_from_slice(self.snapshot.as_slice(), 0))??; Ok(self.mapped_rgns) } From 145b2387209660ab53cb00d8b2b7087184ed18ee Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Mon, 7 Jul 2025 16:23:53 +0100 Subject: [PATCH 05/18] replace evolving a MultiUseSandbox with persist_call_guest_function_by_name Signed-off-by: Jorge Prendes --- src/hyperlight_host/src/func/call_ctx.rs | 39 ----------- .../src/sandbox/initialized_multi_use.rs | 68 +++++++------------ .../src/sandbox_state/transition.rs | 61 ----------------- 3 files changed, 25 insertions(+), 143 deletions(-) diff --git a/src/hyperlight_host/src/func/call_ctx.rs b/src/hyperlight_host/src/func/call_ctx.rs index 168437b97..4ea9c6da5 100644 --- a/src/hyperlight_host/src/func/call_ctx.rs +++ b/src/hyperlight_host/src/func/call_ctx.rs @@ -17,7 +17,6 @@ limitations under the License. use tracing::{Span, instrument}; use super::{ParameterTuple, SupportedReturnType}; -use crate::mem::memory_region::MemoryRegion; use crate::sandbox::Callable; use crate::{MultiUseSandbox, Result}; /// A context for calling guest functions. @@ -57,44 +56,6 @@ impl MultiUseGuestCallContext { self.sbox.restore_state()?; Ok(self.sbox) } - /// Close out the context and get back the internally-stored - /// `MultiUseSandbox`. - /// - /// Note that this method is pub(crate) and does not reset the state of the - /// sandbox. - /// - /// It is intended to be used when evolving a MultiUseSandbox to a new state - /// and is not intended to be called publicly. It allows the state of the guest to be altered - /// during the evolution of one sandbox state to another, enabling the new state created - /// to be captured and stored in the Sandboxes state stack. - /// - pub(crate) fn finish_no_reset(self) -> MultiUseSandbox { - self.sbox - } - - /// Map a region of host memory into the sandbox. - /// - /// Depending on the host platform, there are likely alignment - /// requirements of at least one page for base and len. - /// - /// `rgn.region_type` is ignored, since guest PTEs are not created - /// for the new memory. - /// - /// # Safety - /// It is the caller's responsibility to ensure that the host side - /// of the region remains intact and is not written to until this - /// mapping is removed, either due to the destruction of the - /// sandbox or due to a state rollback - pub unsafe fn map_region(&mut self, rgn: &MemoryRegion) -> Result<()> { - unsafe { self.sbox.map_region(rgn) } - } - - /// Map the contents of a file into the guest at a particular address - /// - /// Returns the length of the mapping - pub fn map_file_cow(&mut self, fp: &std::path::Path, guest_base: u64) -> Result { - self.sbox.map_file_cow(fp, guest_base) - } } impl Callable for MultiUseGuestCallContext { diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 0a566de56..c2ef1523e 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -43,8 +43,7 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::maybe_time_and_emit_guest_call; -use crate::sandbox_state::sandbox::{EvolvableSandbox, Sandbox}; -use crate::sandbox_state::transition::MultiUseContextCallback; +use crate::sandbox_state::sandbox::Sandbox; use crate::{HyperlightError, Result, log_then_return}; /// A sandbox that supports being used Multiple times. @@ -199,6 +198,26 @@ impl MultiUseSandbox { }) } + /// Call a guest function by name, with the given return type and arguments. + /// The changes made to the sandbox are persisted + #[instrument(err(Debug), skip(self, args), parent = Span::current())] + pub fn persist_call_guest_function_by_name( + &mut self, + func_name: &str, + args: impl ParameterTuple, + ) -> Result { + maybe_time_and_emit_guest_call(func_name, || { + let ret = self.call_guest_function_by_name_no_reset( + func_name, + Output::TYPE, + args.into_value(), + ); + let ret = Output::from_value(ret?); + self.mem_mgr.unwrap_mgr_mut().push_state()?; + ret + }) + } + /// Map a region of host memory into the sandbox. /// /// Depending on the host platform, there are likely alignment @@ -360,37 +379,6 @@ impl std::fmt::Debug for MultiUseSandbox { } } -impl<'a, F> - EvolvableSandbox< - MultiUseSandbox, - MultiUseSandbox, - MultiUseContextCallback<'a, MultiUseSandbox, F>, - > for MultiUseSandbox -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()> + 'a, -{ - /// The purpose of this function is to allow multiple states to be associated with a single MultiUseSandbox. - /// - /// An implementation such as HyperlightJs or HyperlightWasm can use this to call guest functions to load JS or WASM code and then evolve the sandbox causing state to be captured. - /// The new MultiUseSandbox can then be used to call guest functions to execute the loaded code. - /// - /// The evolve function creates a new MultiUseCallContext which is then passed to a callback function allowing the - /// callback function to call guest functions as part of the evolve process, once the callback function is complete - /// the context is finished using a crate internal method that does not restore the prior state of the Sandbox. - /// It then creates a mew memory snapshot on the snapshot stack and returns the MultiUseSandbox - #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn evolve( - self, - transition_func: MultiUseContextCallback<'a, MultiUseSandbox, F>, - ) -> Result { - let mut ctx = self.new_call_context(); - transition_func.call(&mut ctx)?; - let mut sbox = ctx.finish_no_reset(); - sbox.mem_mgr.unwrap_mgr_mut().push_state()?; - Ok(sbox) - } -} - #[cfg(test)] mod tests { use std::sync::{Arc, Barrier}; @@ -398,14 +386,13 @@ mod tests { use hyperlight_testing::simple_guest_as_string; - use crate::func::call_ctx::MultiUseGuestCallContext; #[cfg(target_os = "linux")] use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType}; #[cfg(target_os = "linux")] use crate::mem::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory as _}; use crate::sandbox::{Callable, SandboxConfiguration}; use crate::sandbox_state::sandbox::EvolvableSandbox; - use crate::sandbox_state::transition::{MultiUseContextCallback, Noop}; + use crate::sandbox_state::transition::Noop; use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; // Tests to ensure that many (1000) function calls can be made in a call context with a small stack (1K) and heap(14K). @@ -460,18 +447,13 @@ mod tests { let snapshot = sbox.snapshot().unwrap(); - let func = Box::new(|call_ctx: &mut MultiUseGuestCallContext| { - call_ctx.call::("AddToStatic", 5i32)?; - Ok(()) - }); - let transition_func = MultiUseContextCallback::from(func); - let mut sbox = sbox.evolve(transition_func).unwrap(); + sbox.persist_call_guest_function_by_name::("AddToStatic", 5i32).unwrap(); - let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); + let res: i32 = sbox.persist_call_guest_function_by_name("GetStatic", ()).unwrap(); assert_eq!(res, 5); sbox.restore(&snapshot).unwrap(); - let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); + let res: i32 = sbox.persist_call_guest_function_by_name("GetStatic", ()).unwrap(); assert_eq!(res, 0); } diff --git a/src/hyperlight_host/src/sandbox_state/transition.rs b/src/hyperlight_host/src/sandbox_state/transition.rs index f4bf9bbfd..51ba08600 100644 --- a/src/hyperlight_host/src/sandbox_state/transition.rs +++ b/src/hyperlight_host/src/sandbox_state/transition.rs @@ -16,11 +16,7 @@ limitations under the License. use std::marker::PhantomData; -use tracing::{Span, instrument}; - use super::sandbox::Sandbox; -use crate::Result; -use crate::func::call_ctx::MultiUseGuestCallContext; /// Metadata about an evolution. Any `Sandbox` implementation /// that also implements `EvolvableSandbox` can decide the following @@ -82,60 +78,3 @@ impl Default for Noop { } impl TransitionMetadata for Noop {} - -/// A `TransitionMetadata` that calls a callback. The callback function takes -/// a mutable reference to a `MultiUseGuestCallContext` and returns a `Result<()>` -/// to signify success or failure of the function. -/// -/// The function use the context to call guest functions. -/// -/// Construct one of these by passing your callback to -/// `MultiUseContextCallback::from`, as in the following code (assuming `MySandbox` -/// is a `Sandbox` implementation): -/// -/// ```ignore -/// let my_cb_fn: dyn FnOnce(&mut MultiUseGuestCallContext) -> Result<()> = |_sbox| { -/// println!("hello world!"); -/// }; -/// let mutating_cb = MultiUseContextCallback::from(my_cb_fn); -/// ``` -pub struct MultiUseContextCallback<'func, Cur: Sandbox, F> -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()> + 'func, -{ - cur_ph: PhantomData, - fn_life_ph: PhantomData<&'func ()>, - cb: F, -} - -impl TransitionMetadata - for MultiUseContextCallback<'_, Cur, F> -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()>, -{ -} - -impl MultiUseContextCallback<'_, Cur, F> -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()>, -{ - /// Invokes the callback on the provided guest context - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - pub fn call(self, cur: &mut MultiUseGuestCallContext) -> Result<()> { - (self.cb)(cur) - } -} - -impl<'a, Cur: Sandbox, F> From for MultiUseContextCallback<'a, Cur, F> -where - F: FnOnce(&mut MultiUseGuestCallContext) -> Result<()> + 'a, -{ - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - fn from(val: F) -> Self { - MultiUseContextCallback { - cur_ph: PhantomData, - fn_life_ph: PhantomData, - cb: val, - } - } -} From 4f4d8f265e47b91d9cd1adbd1e709e71cec7573e Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Mon, 7 Jul 2025 22:13:37 +0100 Subject: [PATCH 06/18] make all guest function calls persistent Signed-off-by: Jorge Prendes --- src/hyperlight_host/src/func/call_ctx.rs | 20 ++-- src/hyperlight_host/src/mem/mgr.rs | 21 +++++ .../src/sandbox/initialized_multi_use.rs | 93 +++++++++---------- src/hyperlight_host/tests/common/mod.rs | 6 +- src/hyperlight_host/tests/integration_test.rs | 12 --- 5 files changed, 78 insertions(+), 74 deletions(-) diff --git a/src/hyperlight_host/src/func/call_ctx.rs b/src/hyperlight_host/src/func/call_ctx.rs index 4ea9c6da5..63d9309f2 100644 --- a/src/hyperlight_host/src/func/call_ctx.rs +++ b/src/hyperlight_host/src/func/call_ctx.rs @@ -183,27 +183,27 @@ mod tests { let sbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap(); Self { sandbox: sbox } } - pub fn call_add_to_static_multiple_times(mut self, i: i32) -> Result { - let mut ctx = self.sandbox.new_call_context(); + pub fn call_add_to_static_multiple_times(&mut self, i: i32) -> Result<()> { + let snapshot = self.sandbox.snapshot()?; let mut sum: i32 = 0; for n in 0..i { - let result = ctx.call::("AddToStatic", n); + let result = self.sandbox.call_guest_function_by_name::("AddToStatic", n); sum += n; println!("{:?}", result); let result = result.unwrap(); assert_eq!(result, sum); } - let result = ctx.finish(); - assert!(result.is_ok()); - self.sandbox = result.unwrap(); - Ok(self) + self.sandbox.restore(&snapshot)?; + Ok(()) } - pub fn call_add_to_static(mut self, i: i32) -> Result<()> { + pub fn call_add_to_static(&mut self, i: i32) -> Result<()> { + let snapshot = self.sandbox.snapshot()?; for n in 0..i { let result = self .sandbox .call_guest_function_by_name::("AddToStatic", n); + self.sandbox.restore(&snapshot)?; println!("{:?}", result); let result = result.unwrap(); assert_eq!(result, n); @@ -214,14 +214,14 @@ mod tests { #[test] fn ensure_multiusesandbox_multi_calls_dont_reset_state() { - let sandbox = TestSandbox::new(); + let mut sandbox = TestSandbox::new(); let result = sandbox.call_add_to_static_multiple_times(5); assert!(result.is_ok()); } #[test] fn ensure_multiusesandbox_single_calls_do_reset_state() { - let sandbox = TestSandbox::new(); + let mut sandbox = TestSandbox::new(); let result = sandbox.call_add_to_static(5); assert!(result.is_ok()); } diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 4eeeda605..380871be7 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -561,4 +561,25 @@ impl SandboxMemoryManager { self.layout.sandbox_memory_config.get_output_data_size(), ) } + + pub(crate) fn clear_io_buffers(&mut self) { + // Clear the output data buffer + loop { + let Ok(_) = self.shared_mem.try_pop_buffer_into::>( + self.layout.output_data_buffer_offset, + self.layout.sandbox_memory_config.get_output_data_size(), + ) else { + break; + }; + } + // Clear the input data buffer + loop { + let Ok(_) = self.shared_mem.try_pop_buffer_into::>( + self.layout.input_data_buffer_offset, + self.layout.sandbox_memory_config.get_input_data_size(), + ) else { + break; + }; + } + } } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index c2ef1523e..c06d7b0f8 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -180,28 +180,10 @@ impl MultiUseSandbox { Ok(()) } - /// Call a guest function by name, with the given return type and arguments. - #[instrument(err(Debug), skip(self, args), parent = Span::current())] - pub fn call_guest_function_by_name( - &mut self, - func_name: &str, - args: impl ParameterTuple, - ) -> Result { - maybe_time_and_emit_guest_call(func_name, || { - let ret = self.call_guest_function_by_name_no_reset( - func_name, - Output::TYPE, - args.into_value(), - ); - self.restore_state()?; - Output::from_value(ret?) - }) - } - /// Call a guest function by name, with the given return type and arguments. /// The changes made to the sandbox are persisted #[instrument(err(Debug), skip(self, args), parent = Span::current())] - pub fn persist_call_guest_function_by_name( + pub fn call_guest_function_by_name( &mut self, func_name: &str, args: impl ParameterTuple, @@ -213,7 +195,7 @@ impl MultiUseSandbox { args.into_value(), ); let ret = Output::from_value(ret?); - self.mem_mgr.unwrap_mgr_mut().push_state()?; + self.mem_mgr.unwrap_mgr_mut().push_state().unwrap(); ret }) } @@ -298,7 +280,7 @@ impl MultiUseSandbox { ) -> Result { maybe_time_and_emit_guest_call(func_name, || { let ret = self.call_guest_function_by_name_no_reset(func_name, ret_type, args); - self.restore_state()?; + self.mem_mgr.unwrap_mgr_mut().push_state()?; ret }) } @@ -318,35 +300,43 @@ impl MultiUseSandbox { return_type: ReturnType, args: Vec, ) -> Result { - let fc = FunctionCall::new( - function_name.to_string(), - Some(args), - FunctionCallType::Guest, - return_type, - ); - - let buffer: Vec = fc - .try_into() - .map_err(|_| HyperlightError::Error("Failed to serialize FunctionCall".to_string()))?; - - self.get_mgr_wrapper_mut() - .as_mut() - .write_guest_function_call(&buffer)?; - - self.vm.dispatch_call_from_host( - self.dispatch_ptr.clone(), - self.out_hdl.clone(), - self.mem_hdl.clone(), - #[cfg(gdb)] - self.dbg_mem_access_fn.clone(), - )?; + let res = (|| { + let fc = FunctionCall::new( + function_name.to_string(), + Some(args), + FunctionCallType::Guest, + return_type, + ); + + let buffer: Vec = fc.try_into().map_err(|_| { + HyperlightError::Error("Failed to serialize FunctionCall".to_string()) + })?; - self.check_stack_guard()?; - check_for_guest_error(self.get_mgr_wrapper_mut())?; + self.get_mgr_wrapper_mut() + .as_mut() + .write_guest_function_call(&buffer)?; - self.get_mgr_wrapper_mut() - .as_mut() - .get_guest_function_call_result() + self.vm.dispatch_call_from_host( + self.dispatch_ptr.clone(), + self.out_hdl.clone(), + self.mem_hdl.clone(), + #[cfg(gdb)] + self.dbg_mem_access_fn.clone(), + )?; + + self.check_stack_guard()?; + check_for_guest_error(self.get_mgr_wrapper_mut())?; + + self + .get_mgr_wrapper_mut() + .as_mut() + .get_guest_function_call_result() + })(); + + // TODO: Do we want to allow re-entrant guest function calls? + self.get_mgr_wrapper_mut().as_mut().clear_io_buffers(); + + res } /// Get a handle to the interrupt handler for this sandbox, @@ -447,13 +437,14 @@ mod tests { let snapshot = sbox.snapshot().unwrap(); - sbox.persist_call_guest_function_by_name::("AddToStatic", 5i32).unwrap(); + sbox.call_guest_function_by_name::("AddToStatic", 5i32) + .unwrap(); - let res: i32 = sbox.persist_call_guest_function_by_name("GetStatic", ()).unwrap(); + let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); assert_eq!(res, 5); sbox.restore(&snapshot).unwrap(); - let res: i32 = sbox.persist_call_guest_function_by_name("GetStatic", ()).unwrap(); + let res: i32 = sbox.call_guest_function_by_name("GetStatic", ()).unwrap(); assert_eq!(res, 0); } diff --git a/src/hyperlight_host/tests/common/mod.rs b/src/hyperlight_host/tests/common/mod.rs index b3d465bf3..91f05661e 100644 --- a/src/hyperlight_host/tests/common/mod.rs +++ b/src/hyperlight_host/tests/common/mod.rs @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ use hyperlight_host::func::HostFunction; +use hyperlight_host::sandbox::SandboxConfiguration; use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result, UninitializedSandbox}; @@ -34,9 +35,12 @@ pub fn new_uninit() -> Result { /// Use this instead of the `new_uninit` if you want your test to only run with the rust guest, not the c guest pub fn new_uninit_rust() -> Result { + let mut cfg = SandboxConfiguration::default(); + cfg.set_input_data_size(112 * 500 + 7); // 1 MiB + //cfg.set_output_data_size(500 * 100); // 1 MiB UninitializedSandbox::new( GuestBinary::FilePath(simple_guest_as_string().unwrap()), - None, + Some(cfg), ) } diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index 2db32b4a0..936d05c01 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -688,18 +688,6 @@ fn execute_on_heap() { } } -#[test] -fn memory_resets_after_failed_guestcall() { - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - sbox1 - .call_guest_function_by_name::("AddToStaticAndFail", ()) - .unwrap_err(); - let res = sbox1 - .call_guest_function_by_name::("GetStatic", ()) - .unwrap(); - assert_eq!(res, 0, "Expected 0, got {:?}", res); -} - // checks that a recursive function with stack allocation eventually fails with stackoverflow #[test] fn recursive_stack_allocate_overflow() { From 700a5a5a9648be47e83738b71318d732f8e27b3d Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Mon, 7 Jul 2025 22:24:30 +0100 Subject: [PATCH 07/18] remove dead code Signed-off-by: Jorge Prendes --- src/hyperlight_host/src/func/call_ctx.rs | 35 ++++++++----------- .../src/sandbox/initialized_multi_use.rs | 12 +------ 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/hyperlight_host/src/func/call_ctx.rs b/src/hyperlight_host/src/func/call_ctx.rs index 63d9309f2..dd59ea723 100644 --- a/src/hyperlight_host/src/func/call_ctx.rs +++ b/src/hyperlight_host/src/func/call_ctx.rs @@ -47,15 +47,6 @@ impl MultiUseGuestCallContext { pub fn start(sbox: MultiUseSandbox) -> Self { Self { sbox } } - - /// Close out the context and get back the internally-stored - /// `MultiUseSandbox`. Future contexts opened by the returned sandbox - /// will have guest state restored. - #[instrument(err(Debug), skip(self), parent = Span::current())] - pub fn finish(mut self) -> Result { - self.sbox.restore_state()?; - Ok(self.sbox) - } } impl Callable for MultiUseGuestCallContext { @@ -96,8 +87,6 @@ mod tests { use hyperlight_testing::simple_guest_as_string; - use super::MultiUseGuestCallContext; - use crate::sandbox::Callable; use crate::sandbox_state::sandbox::EvolvableSandbox; use crate::sandbox_state::transition::Noop; use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; @@ -134,12 +123,12 @@ mod tests { // requests to execute batches of calls let recv_hdl = thread::spawn(move || { let mut sbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let snapshot = sbox.snapshot().unwrap(); while let Ok(calls) = recv.recv() { - let mut ctx = sbox.new_call_context(); for call in calls { - call.call(&mut ctx); + call.call(&mut sbox); } - sbox = ctx.finish().unwrap(); + sbox.restore(&snapshot).unwrap(); } }); @@ -151,11 +140,15 @@ mod tests { let calls = vec![ TestFuncCall::new(move |ctx| { let msg = format!("Hello {}", i); - let ret: String = ctx.call("Echo", msg.clone()).unwrap(); + let ret: String = ctx + .call_guest_function_by_name("Echo", msg.clone()) + .unwrap(); assert_eq!(ret, msg) }), TestFuncCall::new(move |ctx| { - let ret: i32 = ctx.call("CallMalloc", i + 2).unwrap(); + let ret: i32 = ctx + .call_guest_function_by_name("CallMalloc", i + 2) + .unwrap(); assert_eq!(ret, i + 2) }), ]; @@ -187,7 +180,9 @@ mod tests { let snapshot = self.sandbox.snapshot()?; let mut sum: i32 = 0; for n in 0..i { - let result = self.sandbox.call_guest_function_by_name::("AddToStatic", n); + let result = self + .sandbox + .call_guest_function_by_name::("AddToStatic", n); sum += n; println!("{:?}", result); let result = result.unwrap(); @@ -226,14 +221,14 @@ mod tests { assert!(result.is_ok()); } - struct TestFuncCall(Box); + struct TestFuncCall(Box); impl TestFuncCall { - fn new(f: impl FnOnce(&mut MultiUseGuestCallContext) + Send + 'static) -> Self { + fn new(f: impl FnOnce(&mut MultiUseSandbox) + Send + 'static) -> Self { TestFuncCall(Box::new(f)) } - fn call(self, ctx: &mut MultiUseGuestCallContext) { + fn call(self, ctx: &mut MultiUseSandbox) { (self.0)(ctx); } } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index c06d7b0f8..a4d671ea3 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -285,15 +285,6 @@ impl MultiUseSandbox { }) } - /// Restore the Sandbox's state - #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - pub(crate) fn restore_state(&mut self) -> Result<()> { - let mem_mgr = self.mem_mgr.unwrap_mgr_mut(); - let rgns_to_unmap = mem_mgr.restore_state_from_last_snapshot()?; - unsafe { self.vm.unmap_regions(rgns_to_unmap)? }; - Ok(()) - } - pub(crate) fn call_guest_function_by_name_no_reset( &mut self, function_name: &str, @@ -327,8 +318,7 @@ impl MultiUseSandbox { self.check_stack_guard()?; check_for_guest_error(self.get_mgr_wrapper_mut())?; - self - .get_mgr_wrapper_mut() + self.get_mgr_wrapper_mut() .as_mut() .get_guest_function_call_result() })(); From 272176a8ddbf581a7f4dcbc835ac41974956b05b Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Mon, 7 Jul 2025 22:24:39 +0100 Subject: [PATCH 08/18] fix examples Signed-off-by: Jorge Prendes --- src/hyperlight_host/examples/func_ctx/main.rs | 21 +++++++++---------- src/hyperlight_host/examples/logging/main.rs | 7 +++---- src/hyperlight_host/examples/metrics/main.rs | 7 +++---- .../examples/tracing-otlp/main.rs | 7 +++---- src/hyperlight_host/examples/tracing/main.rs | 7 +++---- 5 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/hyperlight_host/examples/func_ctx/main.rs b/src/hyperlight_host/examples/func_ctx/main.rs index ce427a651..3b9783a91 100644 --- a/src/hyperlight_host/examples/func_ctx/main.rs +++ b/src/hyperlight_host/examples/func_ctx/main.rs @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -use hyperlight_host::func::call_ctx::MultiUseGuestCallContext; -use hyperlight_host::sandbox::{Callable, MultiUseSandbox, UninitializedSandbox}; +use hyperlight_host::sandbox::{MultiUseSandbox, UninitializedSandbox}; use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, Result}; @@ -24,7 +23,7 @@ use hyperlight_testing::simple_guest_as_string; fn main() { // create a new `MultiUseSandbox` configured to run the `simpleguest.exe` // test guest binary - let sbox1: MultiUseSandbox = { + let mut sbox1: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); u_sbox.evolve(Noop::default()) @@ -32,12 +31,11 @@ fn main() { .unwrap(); // create a new call context from the sandbox, then do some calls with it. - let ctx1 = sbox1.new_call_context(); - let sbox2 = do_calls(ctx1).unwrap(); + do_calls(&mut sbox1).unwrap(); + // create a new call context from the returned sandbox, then do some calls // with that one - let ctx2 = sbox2.new_call_context(); - do_calls(ctx2).unwrap(); + do_calls(&mut sbox1).unwrap(); } /// Given a `MultiUseGuestCallContext` derived from an existing @@ -45,11 +43,12 @@ fn main() { /// binary, do several calls against that binary, print their results, then /// call `ctx.finish()` and return the resulting `MultiUseSandbox`. Return an `Err` /// if anything failed. -fn do_calls(mut ctx: MultiUseGuestCallContext) -> Result { - let res: String = ctx.call("Echo", "hello".to_string())?; +fn do_calls(sbox: &mut MultiUseSandbox) -> Result<()> { + let res: String = sbox.call_guest_function_by_name("Echo", "hello".to_string())?; println!("got Echo res: {res}"); - let res: i32 = ctx.call("CallMalloc", 200_i32)?; + let res: i32 = sbox.call_guest_function_by_name("CallMalloc", 200_i32)?; println!("got CallMalloc res: {res}"); - ctx.finish() + + Ok(()) } diff --git a/src/hyperlight_host/examples/logging/main.rs b/src/hyperlight_host/examples/logging/main.rs index ea6e18b31..0ba14835e 100644 --- a/src/hyperlight_host/examples/logging/main.rs +++ b/src/hyperlight_host/examples/logging/main.rs @@ -18,7 +18,6 @@ extern crate hyperlight_host; use std::sync::{Arc, Barrier}; -use hyperlight_host::sandbox::Callable; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; @@ -102,10 +101,10 @@ fn main() -> Result<()> { // Call a function that gets cancelled by the host function 5 times to generate some log entries. for _ in 0..NUM_CALLS { - let mut ctx = multiuse_sandbox.new_call_context(); barrier.wait(); - ctx.call::<()>("Spin", ()).unwrap_err(); - multiuse_sandbox = ctx.finish().unwrap(); + multiuse_sandbox + .call_guest_function_by_name::<()>("Spin", ()) + .unwrap_err(); } thread.join().unwrap(); diff --git a/src/hyperlight_host/examples/metrics/main.rs b/src/hyperlight_host/examples/metrics/main.rs index 5b7cc103f..c6ccb8c47 100644 --- a/src/hyperlight_host/examples/metrics/main.rs +++ b/src/hyperlight_host/examples/metrics/main.rs @@ -18,7 +18,6 @@ extern crate hyperlight_host; use std::sync::{Arc, Barrier}; use std::thread::{JoinHandle, spawn}; -use hyperlight_host::sandbox::Callable; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; @@ -116,10 +115,10 @@ fn do_hyperlight_stuff() { // Call a function that gets cancelled by the host function 5 times to generate some metrics. for _ in 0..NUM_CALLS { - let mut ctx = multiuse_sandbox.new_call_context(); barrier.wait(); - ctx.call::<()>("Spin", ()).unwrap_err(); - multiuse_sandbox = ctx.finish().unwrap(); + multiuse_sandbox + .call_guest_function_by_name::<()>("Spin", ()) + .unwrap_err(); } for join_handle in join_handles { diff --git a/src/hyperlight_host/examples/tracing-otlp/main.rs b/src/hyperlight_host/examples/tracing-otlp/main.rs index 86b6b4e29..cb7d5ba99 100644 --- a/src/hyperlight_host/examples/tracing-otlp/main.rs +++ b/src/hyperlight_host/examples/tracing-otlp/main.rs @@ -26,7 +26,6 @@ use std::io::stdin; use std::sync::{Arc, Barrier, Mutex}; use std::thread::{JoinHandle, spawn}; -use hyperlight_host::sandbox::Callable; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; @@ -184,10 +183,10 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> { uuid = %id, ); let _entered = span.enter(); - let mut ctx = multiuse_sandbox.new_call_context(); barrier.wait(); - ctx.call::<()>("Spin", ()).unwrap_err(); - multiuse_sandbox = ctx.finish().unwrap(); + multiuse_sandbox + .call_guest_function_by_name::<()>("Spin", ()) + .unwrap_err(); } thread.join().expect("Thread panicked"); } diff --git a/src/hyperlight_host/examples/tracing/main.rs b/src/hyperlight_host/examples/tracing/main.rs index dfc680576..66153075e 100644 --- a/src/hyperlight_host/examples/tracing/main.rs +++ b/src/hyperlight_host/examples/tracing/main.rs @@ -19,7 +19,6 @@ extern crate hyperlight_host; use std::sync::{Arc, Barrier}; use std::thread::{JoinHandle, spawn}; -use hyperlight_host::sandbox::Callable; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; @@ -139,10 +138,10 @@ fn run_example() -> Result<()> { uuid = %id, ); let _entered = span.enter(); - let mut ctx = multiuse_sandbox.new_call_context(); barrier.wait(); - ctx.call::<()>("Spin", ()).unwrap_err(); - multiuse_sandbox = ctx.finish().unwrap(); + multiuse_sandbox + .call_guest_function_by_name::<()>("Spin", ()) + .unwrap_err(); } for join_handle in join_handles { From f8a23a2c86cc8563c19ff082bc0f6073e51d362f Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Tue, 8 Jul 2025 10:59:04 +0100 Subject: [PATCH 09/18] Remove MultiUseGuestCallContext Signed-off-by: Jorge Prendes --- src/hyperlight_component_util/src/host.rs | 5 +- src/hyperlight_host/benches/benchmarks.rs | 28 +-- src/hyperlight_host/src/func/call_ctx.rs | 235 ------------------ src/hyperlight_host/src/func/mod.rs | 4 - src/hyperlight_host/src/lib.rs | 3 - .../src/sandbox/initialized_multi_use.rs | 92 +------ .../tests/sandbox_host_tests.rs | 8 +- src/hyperlight_host/tests/wit_test.rs | 4 +- 8 files changed, 28 insertions(+), 351 deletions(-) delete mode 100644 src/hyperlight_host/src/func/call_ctx.rs diff --git a/src/hyperlight_component_util/src/host.rs b/src/hyperlight_component_util/src/host.rs index 4b822b10c..94fe768fa 100644 --- a/src/hyperlight_component_util/src/host.rs +++ b/src/hyperlight_component_util/src/host.rs @@ -357,14 +357,13 @@ fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Com #(#exports)* } impl #ns::#r#trait for ::hyperlight_host::sandbox::UninitializedSandbox { - type Exports = #wrapper_name; + type Exports = #wrapper_name; fn instantiate(mut self, i: I) -> Self::Exports { let rts = register_host_functions(&mut self, i); let noop = ::core::default::Default::default(); let sb = ::hyperlight_host::sandbox_state::sandbox::EvolvableSandbox::evolve(self, noop).unwrap(); - let cc = ::hyperlight_host::func::call_ctx::MultiUseGuestCallContext::start(sb); #wrapper_name { - sb: cc, + sb, rt: rts, } } diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index c9160ff52..a6b5ca734 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -38,13 +38,9 @@ fn guest_call_benchmark(c: &mut Criterion) { // Benchmarks a single guest function call. // The benchmark does **not** include the time to reset the sandbox memory after the call. group.bench_function("guest_call", |b| { - let mut call_ctx = create_multiuse_sandbox().new_call_context(); + let mut sbox = create_multiuse_sandbox(); - b.iter(|| { - call_ctx - .call::("Echo", "hello\n".to_string()) - .unwrap() - }); + b.iter(|| sbox.call::("Echo", "hello\n".to_string()).unwrap()); }); // Benchmarks a single guest function call. @@ -69,11 +65,14 @@ fn guest_call_benchmark(c: &mut Criterion) { .register("HostAdd", |a: i32, b: i32| Ok(a + b)) .unwrap(); - let multiuse_sandbox: MultiUseSandbox = + let mut multiuse_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default()).unwrap(); - let mut call_ctx = multiuse_sandbox.new_call_context(); - b.iter(|| call_ctx.call::("Add", (1_i32, 41_i32)).unwrap()); + b.iter(|| { + multiuse_sandbox + .call::("Add", (1_i32, 41_i32)) + .unwrap() + }); }); group.finish(); @@ -139,17 +138,6 @@ fn sandbox_benchmark(c: &mut Criterion) { b.iter(create_multiuse_sandbox); }); - // Benchmarks the time to create a new sandbox and create a new call context. - // Does **not** include the time to drop the sandbox or the call context. - group.bench_function("create_sandbox_and_call_context", |b| { - b.iter_with_large_drop(|| create_multiuse_sandbox().new_call_context()); - }); - - // Benchmarks the time to create a new sandbox, create a new call context, and drop the call context. - group.bench_function("create_sandbox_and_call_context_and_drop", |b| { - b.iter(|| create_multiuse_sandbox().new_call_context()); - }); - group.finish(); } diff --git a/src/hyperlight_host/src/func/call_ctx.rs b/src/hyperlight_host/src/func/call_ctx.rs deleted file mode 100644 index dd59ea723..000000000 --- a/src/hyperlight_host/src/func/call_ctx.rs +++ /dev/null @@ -1,235 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use tracing::{Span, instrument}; - -use super::{ParameterTuple, SupportedReturnType}; -use crate::sandbox::Callable; -use crate::{MultiUseSandbox, Result}; -/// A context for calling guest functions. -/// -/// Takes ownership of an existing `MultiUseSandbox`. -/// Once created, guest function calls may be made through this and only this context -/// until it is converted back to the `MultiUseSandbox` from which it originated. -/// -/// Upon this conversion,the memory associated with the `MultiUseSandbox` it owns will be reset to the state it was in before -/// this context was created. -/// -/// Calls made through this context will cause state to be retained across calls, until such time as the context -/// is converted back to a `MultiUseSandbox` -/// -/// If dropped, the `MultiUseSandbox` from which it came will be also be dropped as it is owned by the -/// `MultiUseGuestCallContext` until it is converted back to a `MultiUseSandbox` -/// -#[derive(Debug)] -pub struct MultiUseGuestCallContext { - sbox: MultiUseSandbox, -} - -impl MultiUseGuestCallContext { - /// Take ownership of a `MultiUseSandbox` and - /// return a new `MultiUseGuestCallContext` instance. - /// - #[instrument(skip_all, parent = Span::current())] - pub fn start(sbox: MultiUseSandbox) -> Self { - Self { sbox } - } -} - -impl Callable for MultiUseGuestCallContext { - /// Call the guest function called `func_name` with the given arguments - /// `args`, and expect the return value have the same type as - /// `func_ret_type`. - /// - /// Every call to a guest function through this method will be made with the same "context" - /// meaning that the guest state resulting from any previous call will be present/osbservable - /// by the guest function called. - /// - /// If you want to reset state, call `finish()` on this `MultiUseGuestCallContext` - /// and get a new one from the resulting `MultiUseSandbox` - #[instrument(err(Debug),skip(self, args),parent = Span::current())] - fn call( - &mut self, - func_name: &str, - args: impl ParameterTuple, - ) -> Result { - // we are guaranteed to be holding a lock now, since `self` can't - // exist without doing so. Since GuestCallContext is effectively - // !Send (and !Sync), we also don't need to worry about - // synchronization - - let ret = self.sbox.call_guest_function_by_name_no_reset( - func_name, - Output::TYPE, - args.into_value(), - ); - Output::from_value(ret?) - } -} - -#[cfg(test)] -mod tests { - use std::sync::mpsc::sync_channel; - use std::thread::{self, JoinHandle}; - - use hyperlight_testing::simple_guest_as_string; - - use crate::sandbox_state::sandbox::EvolvableSandbox; - use crate::sandbox_state::transition::Noop; - use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; - - fn new_uninit() -> Result { - let path = simple_guest_as_string().map_err(|e| { - HyperlightError::Error(format!("failed to get simple guest path ({e:?})")) - })?; - UninitializedSandbox::new(GuestBinary::FilePath(path), None) - } - - /// Test to create a `MultiUseSandbox`, then call several guest functions - /// on it across different threads. - /// - /// This test works by passing messages between threads using Rust's - /// [mpsc crate](https://doc.rust-lang.org/std/sync/mpsc). Details of this - /// interaction are as follows. - /// - /// One thread acts as the receiver (AKA: consumer) and owns the - /// `MultiUseSandbox`. This receiver fields requests from N senders - /// (AKA: producers) to make batches of calls. - /// - /// Upon receipt of a message to execute a batch, a new - /// `MultiUseGuestCallContext` is created in the receiver thread from the - /// existing `MultiUseSandbox`, and the batch is executed. - /// - /// After the batch is complete, the `MultiUseGuestCallContext` is done - /// and it is converted back to the underlying `MultiUseSandbox` - #[test] - fn test_multi_call_multi_thread() { - let (snd, recv) = sync_channel::>(0); - - // create new receiver thread and on it, begin listening for - // requests to execute batches of calls - let recv_hdl = thread::spawn(move || { - let mut sbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap(); - let snapshot = sbox.snapshot().unwrap(); - while let Ok(calls) = recv.recv() { - for call in calls { - call.call(&mut sbox); - } - sbox.restore(&snapshot).unwrap(); - } - }); - - // create new sender threads - let send_handles: Vec> = (0..10) - .map(|i| { - let sender = snd.clone(); - thread::spawn(move || { - let calls = vec![ - TestFuncCall::new(move |ctx| { - let msg = format!("Hello {}", i); - let ret: String = ctx - .call_guest_function_by_name("Echo", msg.clone()) - .unwrap(); - assert_eq!(ret, msg) - }), - TestFuncCall::new(move |ctx| { - let ret: i32 = ctx - .call_guest_function_by_name("CallMalloc", i + 2) - .unwrap(); - assert_eq!(ret, i + 2) - }), - ]; - sender.send(calls).unwrap(); - }) - }) - .collect(); - - for hdl in send_handles { - hdl.join().unwrap(); - } - // after all sender threads are done, drop the sender itself - // so the receiver thread can exit. then, ensure the receiver - // thread has exited. - drop(snd); - recv_hdl.join().unwrap(); - } - - pub struct TestSandbox { - sandbox: MultiUseSandbox, - } - - impl TestSandbox { - pub fn new() -> Self { - let sbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap(); - Self { sandbox: sbox } - } - pub fn call_add_to_static_multiple_times(&mut self, i: i32) -> Result<()> { - let snapshot = self.sandbox.snapshot()?; - let mut sum: i32 = 0; - for n in 0..i { - let result = self - .sandbox - .call_guest_function_by_name::("AddToStatic", n); - sum += n; - println!("{:?}", result); - let result = result.unwrap(); - assert_eq!(result, sum); - } - self.sandbox.restore(&snapshot)?; - Ok(()) - } - - pub fn call_add_to_static(&mut self, i: i32) -> Result<()> { - let snapshot = self.sandbox.snapshot()?; - for n in 0..i { - let result = self - .sandbox - .call_guest_function_by_name::("AddToStatic", n); - self.sandbox.restore(&snapshot)?; - println!("{:?}", result); - let result = result.unwrap(); - assert_eq!(result, n); - } - Ok(()) - } - } - - #[test] - fn ensure_multiusesandbox_multi_calls_dont_reset_state() { - let mut sandbox = TestSandbox::new(); - let result = sandbox.call_add_to_static_multiple_times(5); - assert!(result.is_ok()); - } - - #[test] - fn ensure_multiusesandbox_single_calls_do_reset_state() { - let mut sandbox = TestSandbox::new(); - let result = sandbox.call_add_to_static(5); - assert!(result.is_ok()); - } - - struct TestFuncCall(Box); - - impl TestFuncCall { - fn new(f: impl FnOnce(&mut MultiUseSandbox) + Send + 'static) -> Self { - TestFuncCall(Box::new(f)) - } - - fn call(self, ctx: &mut MultiUseSandbox) { - (self.0)(ctx); - } - } -} diff --git a/src/hyperlight_host/src/func/mod.rs b/src/hyperlight_host/src/func/mod.rs index a0efe113e..57b69dbc4 100644 --- a/src/hyperlight_host/src/func/mod.rs +++ b/src/hyperlight_host/src/func/mod.rs @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/// Context structures used to allow the user to call one or more guest -/// functions on the same Hyperlight sandbox instance, all from within the -/// same state and mutual exclusion context. -pub mod call_ctx; /// Functionality to check for errors after a guest call pub(crate) mod guest_err; /// Definitions and functionality to enable guest-to-host function calling, diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 2c52729a5..5eb5c165a 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -85,9 +85,6 @@ pub use sandbox::is_hypervisor_present; /// The re-export for the `GuestBinary` type pub use sandbox::uninitialized::GuestBinary; -/// The re-export for the `MultiUseGuestCallContext` type` -pub use crate::func::call_ctx::MultiUseGuestCallContext; - /// The universal `Result` type used throughout the Hyperlight codebase. pub type Result = core::result::Result; diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index a4d671ea3..abecaebf2 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -29,8 +29,7 @@ use tracing::{Span, instrument}; use super::host_funcs::FunctionRegistry; use super::snapshot::Snapshot; -use super::{MemMgrWrapper, WrapperGetter}; -use crate::func::call_ctx::MultiUseGuestCallContext; +use super::{Callable, MemMgrWrapper, WrapperGetter}; use crate::func::guest_err::check_for_guest_error; use crate::func::{ParameterTuple, SupportedReturnType}; #[cfg(gdb)] @@ -94,75 +93,6 @@ impl MultiUseSandbox { } } - /// Create a new `MultiUseCallContext` suitable for making 0 or more - /// calls to guest functions within the same context. - /// - /// Since this function consumes `self`, the returned - /// `MultiUseGuestCallContext` is guaranteed mutual exclusion for calling - /// functions within the sandbox. This guarantee is enforced at compile - /// time, and no locks, atomics, or any other mutual exclusion mechanisms - /// are used at runtime. - /// - /// If you have called this function, have a `MultiUseGuestCallContext`, - /// and wish to "return" it to a `MultiUseSandbox`, call the `finish` - /// method on the context. - /// - /// Example usage (compiled as a "no_run" doctest since the test binary - /// will not be found): - /// - /// ```no_run - /// use hyperlight_host::sandbox::{UninitializedSandbox, MultiUseSandbox}; - /// use hyperlight_common::flatbuffer_wrappers::function_types::{ReturnType, ParameterValue, ReturnValue}; - /// use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; - /// use hyperlight_host::sandbox_state::transition::Noop; - /// use hyperlight_host::GuestBinary; - /// - /// // First, create a new uninitialized sandbox, then evolve it to become - /// // an initialized, single-use one. - /// let u_sbox = UninitializedSandbox::new( - /// GuestBinary::FilePath("some_guest_binary".to_string()), - /// None, - /// ).unwrap(); - /// let sbox: MultiUseSandbox = u_sbox.evolve(Noop::default()).unwrap(); - /// // Next, create a new call context from the single-use sandbox. - /// // After this line, your code will not compile if you try to use the - /// // original `sbox` variable. - /// let mut ctx = sbox.new_call_context(); - /// - /// // Do a guest call with the context. Assumes that the loaded binary - /// // ("some_guest_binary") has a function therein called "SomeGuestFunc" - /// // that takes a single integer argument and returns an integer. - /// match ctx.call( - /// "SomeGuestFunc", - /// ReturnType::Int, - /// Some(vec![ParameterValue::Int(1)]) - /// ) { - /// Ok(ReturnValue::Int(i)) => println!( - /// "got successful return value {}", - /// i, - /// ), - /// other => panic!( - /// "failed to get return value as expected ({:?})", - /// other, - /// ), - /// }; - /// // You can make further calls with the same context if you want. - /// // Otherwise, `ctx` will be dropped and all resources, including the - /// // underlying `MultiUseSandbox`, will be released and no further - /// // contexts can be created from that sandbox. - /// // - /// // If you want to avoid - /// // that behavior, call `finish` to convert the context back to - /// // the original `MultiUseSandbox`, as follows: - /// let _orig_sbox = ctx.finish(); - /// // Now, you can operate on the original sandbox again (i.e. add more - /// // host functions etc...), create new contexts, and so on. - /// ``` - #[instrument(skip_all, parent = Span::current())] - pub fn new_call_context(self) -> MultiUseGuestCallContext { - MultiUseGuestCallContext::start(self) - } - /// Create a snapshot of the current state of the sandbox's memory. #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn snapshot(&mut self) -> Result { @@ -183,7 +113,7 @@ impl MultiUseSandbox { /// Call a guest function by name, with the given return type and arguments. /// The changes made to the sandbox are persisted #[instrument(err(Debug), skip(self, args), parent = Span::current())] - pub fn call_guest_function_by_name( + pub fn call_guest_function_by_name( &mut self, func_name: &str, args: impl ParameterTuple, @@ -336,6 +266,12 @@ impl MultiUseSandbox { } } +impl Callable for MultiUseSandbox { + fn call(&mut self, func_name: &str, args: impl ParameterTuple) -> Result { + self.call_guest_function_by_name(func_name, args) + } +} + impl WrapperGetter for MultiUseSandbox { fn get_mgr_wrapper(&self) -> &MemMgrWrapper { &self.mem_mgr @@ -383,30 +319,26 @@ mod tests { cfg.set_heap_size(20 * 1024); cfg.set_stack_size(16 * 1024); - let sbox1: MultiUseSandbox = { + let mut sbox1: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), Some(cfg)).unwrap(); u_sbox.evolve(Noop::default()) } .unwrap(); - let mut ctx = sbox1.new_call_context(); - for _ in 0..1000 { - ctx.call::("Echo", "hello".to_string()).unwrap(); + sbox1.call::("Echo", "hello".to_string()).unwrap(); } - let sbox2: MultiUseSandbox = { + let mut sbox2: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), Some(cfg)).unwrap(); u_sbox.evolve(Noop::default()) } .unwrap(); - let mut ctx = sbox2.new_call_context(); - for i in 0..1000 { - ctx.call::( + sbox2.call::( "PrintUsingPrintf", format!("Hello World {}\n", i).to_string(), ) diff --git a/src/hyperlight_host/tests/sandbox_host_tests.rs b/src/hyperlight_host/tests/sandbox_host_tests.rs index 1c8bf92b6..7b113813e 100644 --- a/src/hyperlight_host/tests/sandbox_host_tests.rs +++ b/src/hyperlight_host/tests/sandbox_host_tests.rs @@ -35,16 +35,16 @@ use crate::common::{get_callbackguest_uninit_sandboxes, get_simpleguest_sandboxe #[test] #[cfg_attr(target_os = "windows", serial)] // using LoadLibrary requires serial tests fn pass_byte_array() { - for sandbox in get_simpleguest_sandboxes(None).into_iter() { - let mut ctx = sandbox.new_call_context(); + for mut sandbox in get_simpleguest_sandboxes(None).into_iter() { const LEN: usize = 10; let bytes = vec![1u8; LEN]; - let res: Vec = ctx + let res: Vec = sandbox .call("SetByteArrayToZero", bytes.clone()) .expect("Expected VecBytes"); assert_eq!(res, [0; LEN]); - ctx.call::("SetByteArrayToZeroNoLength", bytes.clone()) + sandbox + .call::("SetByteArrayToZeroNoLength", bytes.clone()) .unwrap_err(); // missing length param } } diff --git a/src/hyperlight_host/tests/wit_test.rs b/src/hyperlight_host/tests/wit_test.rs index e42441dd8..158945148 100644 --- a/src/hyperlight_host/tests/wit_test.rs +++ b/src/hyperlight_host/tests/wit_test.rs @@ -18,7 +18,7 @@ limitations under the License. use std::sync::{Arc, Mutex}; use hyperlight_common::resource::BorrowedResourceGuard; -use hyperlight_host::{GuestBinary, MultiUseGuestCallContext, UninitializedSandbox}; +use hyperlight_host::{GuestBinary, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::wit_guest_as_string; extern crate alloc; @@ -238,7 +238,7 @@ impl test::wit::TestImports for Host { } } -fn sb() -> TestSandbox { +fn sb() -> TestSandbox { let path = wit_guest_as_string().unwrap(); let guest_path = GuestBinary::FilePath(path); let uninit = UninitializedSandbox::new(guest_path, None).unwrap(); From 262bb1c603439f4dd93f36bc6b15172caaedc68c Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Tue, 8 Jul 2025 14:00:15 +0100 Subject: [PATCH 10/18] remove EvolvableSandbox trait Signed-off-by: Jorge Prendes --- README.md | 1 - fuzz/fuzz_targets/guest_call.rs | 1 - fuzz/fuzz_targets/host_call.rs | 1 - fuzz/fuzz_targets/host_print.rs | 1 - src/hyperlight_component_util/src/host.rs | 3 +-- src/hyperlight_host/benches/benchmarks.rs | 1 - src/hyperlight_host/examples/func_ctx/main.rs | 1 - .../examples/guest-debugging/main.rs | 1 - src/hyperlight_host/examples/hello-world/main.rs | 1 - src/hyperlight_host/examples/logging/main.rs | 1 - src/hyperlight_host/examples/metrics/main.rs | 1 - .../examples/tracing-chrome/main.rs | 1 - src/hyperlight_host/examples/tracing-otlp/main.rs | 1 - src/hyperlight_host/examples/tracing-tracy/main.rs | 1 - src/hyperlight_host/examples/tracing/main.rs | 1 - src/hyperlight_host/src/metrics/mod.rs | 1 - .../src/sandbox/initialized_multi_use.rs | 1 - src/hyperlight_host/src/sandbox/mod.rs | 1 - src/hyperlight_host/src/sandbox/uninitialized.rs | 12 ++---------- src/hyperlight_host/src/sandbox_state/sandbox.rs | 14 ++------------ .../src/sandbox_state/transition.rs | 2 ++ src/hyperlight_host/tests/common/mod.rs | 1 - src/hyperlight_host/tests/integration_test.rs | 1 - src/hyperlight_host/tests/sandbox_host_tests.rs | 1 - 24 files changed, 7 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 042ff7bf2..d00408635 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ It is followed by an example of a simple guest application using the Hyperlight ```rust use std::thread; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; diff --git a/fuzz/fuzz_targets/guest_call.rs b/fuzz/fuzz_targets/guest_call.rs index 2e0fcee00..8d9ee1702 100644 --- a/fuzz/fuzz_targets/guest_call.rs +++ b/fuzz/fuzz_targets/guest_call.rs @@ -20,7 +20,6 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::func::{ParameterValue, ReturnType}; use hyperlight_host::sandbox::uninitialized::GuestBinary; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; diff --git a/fuzz/fuzz_targets/host_call.rs b/fuzz/fuzz_targets/host_call.rs index bdd8ad760..a20a521d1 100644 --- a/fuzz/fuzz_targets/host_call.rs +++ b/fuzz/fuzz_targets/host_call.rs @@ -20,7 +20,6 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::func::{ParameterValue, ReturnType}; use hyperlight_host::sandbox::uninitialized::GuestBinary; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{HyperlightError, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; diff --git a/fuzz/fuzz_targets/host_print.rs b/fuzz/fuzz_targets/host_print.rs index 0a7e90d40..49080ac34 100644 --- a/fuzz/fuzz_targets/host_print.rs +++ b/fuzz/fuzz_targets/host_print.rs @@ -3,7 +3,6 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::sandbox::uninitialized::GuestBinary; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; diff --git a/src/hyperlight_component_util/src/host.rs b/src/hyperlight_component_util/src/host.rs index 94fe768fa..7071d5834 100644 --- a/src/hyperlight_component_util/src/host.rs +++ b/src/hyperlight_component_util/src/host.rs @@ -347,7 +347,6 @@ fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Com pub(crate) rt: ::std::sync::Arc<::std::sync::Mutex<#rtsid>>, } pub(crate) fn register_host_functions(sb: &mut S, i: I) -> ::std::sync::Arc<::std::sync::Mutex<#rtsid>> { - use ::hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; let rts = ::std::sync::Arc::new(::std::sync::Mutex::new(#rtsid::new())); let #import_id = ::std::sync::Arc::new(::std::sync::Mutex::new(i)); #(#imports)* @@ -361,7 +360,7 @@ fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Com fn instantiate(mut self, i: I) -> Self::Exports { let rts = register_host_functions(&mut self, i); let noop = ::core::default::Default::default(); - let sb = ::hyperlight_host::sandbox_state::sandbox::EvolvableSandbox::evolve(self, noop).unwrap(); + let sb = self.evolve(noop).unwrap(); #wrapper_name { sb, rt: rts, diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index a6b5ca734..182c3ad88 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -19,7 +19,6 @@ use hyperlight_host::GuestBinary; use hyperlight_host::sandbox::{ Callable, MultiUseSandbox, SandboxConfiguration, UninitializedSandbox, }; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_testing::simple_guest_as_string; diff --git a/src/hyperlight_host/examples/func_ctx/main.rs b/src/hyperlight_host/examples/func_ctx/main.rs index 3b9783a91..5161c10ee 100644 --- a/src/hyperlight_host/examples/func_ctx/main.rs +++ b/src/hyperlight_host/examples/func_ctx/main.rs @@ -15,7 +15,6 @@ limitations under the License. */ use hyperlight_host::sandbox::{MultiUseSandbox, UninitializedSandbox}; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index f33ed511f..6c5876596 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -19,7 +19,6 @@ use std::thread; use hyperlight_host::sandbox::SandboxConfiguration; #[cfg(gdb)] use hyperlight_host::sandbox::config::DebugInfo; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; diff --git a/src/hyperlight_host/examples/hello-world/main.rs b/src/hyperlight_host/examples/hello-world/main.rs index 57c0b4398..834ca09df 100644 --- a/src/hyperlight_host/examples/hello-world/main.rs +++ b/src/hyperlight_host/examples/hello-world/main.rs @@ -16,7 +16,6 @@ limitations under the License. #![allow(clippy::disallowed_macros)] use std::thread; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; diff --git a/src/hyperlight_host/examples/logging/main.rs b/src/hyperlight_host/examples/logging/main.rs index 0ba14835e..0b4eb4e57 100644 --- a/src/hyperlight_host/examples/logging/main.rs +++ b/src/hyperlight_host/examples/logging/main.rs @@ -19,7 +19,6 @@ extern crate hyperlight_host; use std::sync::{Arc, Barrier}; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; use hyperlight_testing::simple_guest_as_string; diff --git a/src/hyperlight_host/examples/metrics/main.rs b/src/hyperlight_host/examples/metrics/main.rs index c6ccb8c47..9cc13e134 100644 --- a/src/hyperlight_host/examples/metrics/main.rs +++ b/src/hyperlight_host/examples/metrics/main.rs @@ -19,7 +19,6 @@ use std::sync::{Arc, Barrier}; use std::thread::{JoinHandle, spawn}; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; use hyperlight_testing::simple_guest_as_string; diff --git a/src/hyperlight_host/examples/tracing-chrome/main.rs b/src/hyperlight_host/examples/tracing-chrome/main.rs index a93e03fab..ba08a1ebc 100644 --- a/src/hyperlight_host/examples/tracing-chrome/main.rs +++ b/src/hyperlight_host/examples/tracing-chrome/main.rs @@ -15,7 +15,6 @@ limitations under the License. */ #![allow(clippy::disallowed_macros)] use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; use hyperlight_testing::simple_guest_as_string; diff --git a/src/hyperlight_host/examples/tracing-otlp/main.rs b/src/hyperlight_host/examples/tracing-otlp/main.rs index cb7d5ba99..c6362c5de 100644 --- a/src/hyperlight_host/examples/tracing-otlp/main.rs +++ b/src/hyperlight_host/examples/tracing-otlp/main.rs @@ -27,7 +27,6 @@ use std::sync::{Arc, Barrier, Mutex}; use std::thread::{JoinHandle, spawn}; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result as HyperlightResult}; use hyperlight_testing::simple_guest_as_string; diff --git a/src/hyperlight_host/examples/tracing-tracy/main.rs b/src/hyperlight_host/examples/tracing-tracy/main.rs index 615b59c38..68cfbcb4c 100644 --- a/src/hyperlight_host/examples/tracing-tracy/main.rs +++ b/src/hyperlight_host/examples/tracing-tracy/main.rs @@ -15,7 +15,6 @@ limitations under the License. */ #![allow(clippy::disallowed_macros)] use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; use hyperlight_testing::simple_guest_as_string; diff --git a/src/hyperlight_host/examples/tracing/main.rs b/src/hyperlight_host/examples/tracing/main.rs index 66153075e..4e981b5e0 100644 --- a/src/hyperlight_host/examples/tracing/main.rs +++ b/src/hyperlight_host/examples/tracing/main.rs @@ -20,7 +20,6 @@ use std::sync::{Arc, Barrier}; use std::thread::{JoinHandle, spawn}; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; use hyperlight_testing::simple_guest_as_string; diff --git a/src/hyperlight_host/src/metrics/mod.rs b/src/hyperlight_host/src/metrics/mod.rs index 3181d3b89..bc34b38f7 100644 --- a/src/hyperlight_host/src/metrics/mod.rs +++ b/src/hyperlight_host/src/metrics/mod.rs @@ -93,7 +93,6 @@ mod tests { use metrics_util::CompositeKey; use super::*; - use crate::sandbox_state::sandbox::EvolvableSandbox; use crate::sandbox_state::transition::Noop; use crate::{GuestBinary, UninitializedSandbox}; diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index abecaebf2..5d6655f01 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -307,7 +307,6 @@ mod tests { #[cfg(target_os = "linux")] use crate::mem::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory as _}; use crate::sandbox::{Callable, SandboxConfiguration}; - use crate::sandbox_state::sandbox::EvolvableSandbox; use crate::sandbox_state::transition::Noop; use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 48638a762..529fc4ffc 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -104,7 +104,6 @@ mod tests { use hyperlight_testing::simple_guest_as_string; use crate::sandbox::uninitialized::GuestBinary; - use crate::sandbox_state::sandbox::EvolvableSandbox; use crate::sandbox_state::transition::Noop; use crate::{MultiUseSandbox, UninitializedSandbox, new_error}; diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index e27f91ff2..1dcb8e7ef 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -34,7 +34,6 @@ use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags} use crate::mem::mgr::{STACK_COOKIE_LEN, SandboxMemoryManager}; use crate::mem::shared_mem::ExclusiveSharedMemory; use crate::sandbox::SandboxConfiguration; -use crate::sandbox_state::sandbox::EvolvableSandbox; use crate::sandbox_state::transition::Noop; use crate::{MultiUseSandbox, Result, log_then_return, new_error}; @@ -110,16 +109,10 @@ impl crate::sandbox_state::sandbox::Sandbox for UninitializedSandbox { } } -impl - EvolvableSandbox< - UninitializedSandbox, - MultiUseSandbox, - Noop, - > for UninitializedSandbox -{ +impl UninitializedSandbox { /// Evolve `self` to a `MultiUseSandbox` without any additional metadata. #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - fn evolve(self, _: Noop) -> Result { + pub fn evolve(self, _: Noop) -> Result { evolve_impl_multi_use(self) } } @@ -433,7 +426,6 @@ mod tests { use crate::sandbox::SandboxConfiguration; use crate::sandbox::uninitialized::{GuestBinary, GuestEnvironment}; - use crate::sandbox_state::sandbox::EvolvableSandbox; use crate::sandbox_state::transition::Noop; use crate::{MultiUseSandbox, Result, UninitializedSandbox, new_error}; diff --git a/src/hyperlight_host/src/sandbox_state/sandbox.rs b/src/hyperlight_host/src/sandbox_state/sandbox.rs index b00c490e7..b88738835 100644 --- a/src/hyperlight_host/src/sandbox_state/sandbox.rs +++ b/src/hyperlight_host/src/sandbox_state/sandbox.rs @@ -18,7 +18,6 @@ use std::fmt::Debug; use tracing::{Span, instrument}; -use super::transition::TransitionMetadata; use crate::{Result, new_error}; /// The minimal functionality of a Hyperlight sandbox. Most of the types @@ -29,9 +28,8 @@ use crate::{Result, new_error}; /// in the state machine to which it belongs, and it may know how to "evolve" /// into a next state. That "next state" may in turn know how to roll back /// to the root node. -/// -/// These transitions are expressed as `EvolvableSandbox` implementations -/// any `Sandbox` implementation can opt into. +/// +/// TODO: fix this comment, it is not accurate anymore pub trait Sandbox: Sized + Debug { /// Check to ensure the current stack cookie matches the one that /// was selected when the stack was constructed. @@ -61,11 +59,3 @@ pub trait UninitializedSandbox: Sandbox { /// Retrieves mutable reference to strongly typed `UninitializedSandbox` fn get_uninitialized_sandbox_mut(&mut self) -> &mut crate::sandbox::UninitializedSandbox; } - -/// A `Sandbox` that knows how to "evolve" into a next state. -pub trait EvolvableSandbox>: - Sandbox -{ - /// Evolve `Self` to `Next` providing Metadata. - fn evolve(self, tsn: T) -> Result; -} diff --git a/src/hyperlight_host/src/sandbox_state/transition.rs b/src/hyperlight_host/src/sandbox_state/transition.rs index 51ba08600..7a873dbf2 100644 --- a/src/hyperlight_host/src/sandbox_state/transition.rs +++ b/src/hyperlight_host/src/sandbox_state/transition.rs @@ -18,6 +18,8 @@ use std::marker::PhantomData; use super::sandbox::Sandbox; +/// TODO: fix this comment, it is not accurate anymore. +/// /// Metadata about an evolution. Any `Sandbox` implementation /// that also implements `EvolvableSandbox` can decide the following /// things in a type-safe way: diff --git a/src/hyperlight_host/tests/common/mod.rs b/src/hyperlight_host/tests/common/mod.rs index 91f05661e..75d7c27be 100644 --- a/src/hyperlight_host/tests/common/mod.rs +++ b/src/hyperlight_host/tests/common/mod.rs @@ -15,7 +15,6 @@ limitations under the License. */ use hyperlight_host::func::HostFunction; use hyperlight_host::sandbox::SandboxConfiguration; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result, UninitializedSandbox}; use hyperlight_testing::{ diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index 936d05c01..c7ab9329a 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -22,7 +22,6 @@ use std::time::Duration; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::mem::PAGE_SIZE; use hyperlight_host::sandbox::SandboxConfiguration; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, HyperlightError, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simplelogger::{LOGGER, SimpleLogger}; diff --git a/src/hyperlight_host/tests/sandbox_host_tests.rs b/src/hyperlight_host/tests/sandbox_host_tests.rs index 7b113813e..49697a0ed 100644 --- a/src/hyperlight_host/tests/sandbox_host_tests.rs +++ b/src/hyperlight_host/tests/sandbox_host_tests.rs @@ -20,7 +20,6 @@ use std::sync::{Arc, Mutex}; use common::new_uninit; use hyperlight_host::sandbox::{Callable, SandboxConfiguration}; -use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox; use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{ GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox, new_error, From 2680090ddf08dc8e1aaa9fd4caa3cd24bfb83693 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Tue, 8 Jul 2025 14:02:05 +0100 Subject: [PATCH 11/18] remove TransitionMetadata Signed-off-by: Jorge Prendes --- .../src/sandbox_state/transition.rs | 44 ------------------- 1 file changed, 44 deletions(-) diff --git a/src/hyperlight_host/src/sandbox_state/transition.rs b/src/hyperlight_host/src/sandbox_state/transition.rs index 7a873dbf2..1c918f06a 100644 --- a/src/hyperlight_host/src/sandbox_state/transition.rs +++ b/src/hyperlight_host/src/sandbox_state/transition.rs @@ -18,48 +18,6 @@ use std::marker::PhantomData; use super::sandbox::Sandbox; -/// TODO: fix this comment, it is not accurate anymore. -/// -/// Metadata about an evolution. Any `Sandbox` implementation -/// that also implements `EvolvableSandbox` can decide the following -/// things in a type-safe way: -/// -/// 1. That transition is possible -/// 2. That transition requires a specific kind of metadata -/// -/// For example, if you have the following structs: -/// -/// ```ignore -/// struct MySandbox1 {} -/// struct MySandbox2 {} -/// -/// impl Sandbox for MySandbox1 {...} -/// impl Sandbox for MySandbox2 {...} -/// ``` -/// -/// ...then you can define a metadata-free evolve transition between -/// `MySandbox1` and `MySandbox2` as follows: -/// -/// ```ignore -/// impl EvolvableSandbox< -/// MySandbox1, -/// MySandbox2, -/// Noop -/// > for MySandbox1 { -/// fn evolve( -/// self, -/// _: Noop -/// ) -> Result { -/// Ok(MySandbox2{}) -/// } -/// } -/// -/// ``` -/// -/// Most transitions will likely involve `Noop`, but some may involve -/// implementing their own. -pub trait TransitionMetadata {} - /// Transition metadata that contains and does nothing. `Noop` is a /// placeholder when you want to implement an `EvolvableSandbox` /// that needs no additional metadata to succeed. @@ -78,5 +36,3 @@ impl Default for Noop { } } } - -impl TransitionMetadata for Noop {} From ced5bbd5afc4ada192891714f186210c5fdf2461 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Tue, 8 Jul 2025 14:14:11 +0100 Subject: [PATCH 12/18] remove Noop transition Signed-off-by: Jorge Prendes --- README.md | 3 +- fuzz/fuzz_targets/guest_call.rs | 3 +- fuzz/fuzz_targets/host_call.rs | 3 +- fuzz/fuzz_targets/host_print.rs | 3 +- src/hyperlight_component_util/src/host.rs | 3 +- src/hyperlight_host/benches/benchmarks.rs | 7 +- src/hyperlight_host/examples/func_ctx/main.rs | 3 +- .../examples/guest-debugging/main.rs | 5 +- .../examples/hello-world/main.rs | 3 +- src/hyperlight_host/examples/logging/main.rs | 13 +--- src/hyperlight_host/examples/metrics/main.rs | 13 +--- .../examples/tracing-chrome/main.rs | 5 +- .../examples/tracing-otlp/main.rs | 8 +-- .../examples/tracing-tracy/main.rs | 5 +- src/hyperlight_host/examples/tracing/main.rs | 13 +--- src/hyperlight_host/src/metrics/mod.rs | 3 +- .../src/sandbox/initialized_multi_use.rs | 21 +++--- src/hyperlight_host/src/sandbox/mod.rs | 3 +- .../src/sandbox/uninitialized.rs | 20 +++--- src/hyperlight_host/src/sandbox_state/mod.rs | 2 - .../src/sandbox_state/transition.rs | 38 ----------- src/hyperlight_host/tests/common/mod.rs | 3 +- src/hyperlight_host/tests/integration_test.rs | 67 +++++++++---------- .../tests/sandbox_host_tests.rs | 7 +- 24 files changed, 85 insertions(+), 169 deletions(-) delete mode 100644 src/hyperlight_host/src/sandbox_state/transition.rs diff --git a/README.md b/README.md index d00408635..6ca4ec826 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ It is followed by an example of a simple guest application using the Hyperlight ```rust use std::thread; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; fn main() -> hyperlight_host::Result<()> { @@ -53,7 +52,7 @@ fn main() -> hyperlight_host::Result<()> { // Note: This function is unused by the guest code below, it's just here for demonstration purposes // Initialize sandbox to be able to call host functions - let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default())?; + let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve()?; // Call a function in the guest let message = "Hello, World! I am executing inside of a VM :)\n".to_string(); diff --git a/fuzz/fuzz_targets/guest_call.rs b/fuzz/fuzz_targets/guest_call.rs index 8d9ee1702..bc0ff163f 100644 --- a/fuzz/fuzz_targets/guest_call.rs +++ b/fuzz/fuzz_targets/guest_call.rs @@ -20,7 +20,6 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::func::{ParameterValue, ReturnType}; use hyperlight_host::sandbox::uninitialized::GuestBinary; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; use libfuzzer_sys::fuzz_target; @@ -37,7 +36,7 @@ fuzz_target!( ) .unwrap(); - let mu_sbox: MultiUseSandbox = u_sbox.evolve(Noop::default()).unwrap(); + let mu_sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); }, diff --git a/fuzz/fuzz_targets/host_call.rs b/fuzz/fuzz_targets/host_call.rs index a20a521d1..5c72a98e5 100644 --- a/fuzz/fuzz_targets/host_call.rs +++ b/fuzz/fuzz_targets/host_call.rs @@ -20,7 +20,6 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::func::{ParameterValue, ReturnType}; use hyperlight_host::sandbox::uninitialized::GuestBinary; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{HyperlightError, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; use libfuzzer_sys::fuzz_target; @@ -36,7 +35,7 @@ fuzz_target!( ) .unwrap(); - let mu_sbox: MultiUseSandbox = u_sbox.evolve(Noop::default()).unwrap(); + let mu_sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); }, diff --git a/fuzz/fuzz_targets/host_print.rs b/fuzz/fuzz_targets/host_print.rs index 49080ac34..c9c889e9e 100644 --- a/fuzz/fuzz_targets/host_print.rs +++ b/fuzz/fuzz_targets/host_print.rs @@ -3,7 +3,6 @@ use std::sync::{Mutex, OnceLock}; use hyperlight_host::sandbox::uninitialized::GuestBinary; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simple_guest_for_fuzzing_as_string; use libfuzzer_sys::{Corpus, fuzz_target}; @@ -22,7 +21,7 @@ fuzz_target!( ) .unwrap(); - let mu_sbox: MultiUseSandbox = u_sbox.evolve(Noop::default()).unwrap(); + let mu_sbox: MultiUseSandbox = u_sbox.evolve().unwrap(); SANDBOX.set(Mutex::new(mu_sbox)).unwrap(); }, diff --git a/src/hyperlight_component_util/src/host.rs b/src/hyperlight_component_util/src/host.rs index 7071d5834..b8a194dd2 100644 --- a/src/hyperlight_component_util/src/host.rs +++ b/src/hyperlight_component_util/src/host.rs @@ -359,8 +359,7 @@ fn emit_component<'a, 'b, 'c>(s: &'c mut State<'a, 'b>, wn: WitName, ct: &'c Com type Exports = #wrapper_name; fn instantiate(mut self, i: I) -> Self::Exports { let rts = register_host_functions(&mut self, i); - let noop = ::core::default::Default::default(); - let sb = self.evolve(noop).unwrap(); + let sb = self.evolve().unwrap(); #wrapper_name { sb, rt: rts, diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index 182c3ad88..f2eb5727c 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -19,7 +19,6 @@ use hyperlight_host::GuestBinary; use hyperlight_host::sandbox::{ Callable, MultiUseSandbox, SandboxConfiguration, UninitializedSandbox, }; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_testing::simple_guest_as_string; fn create_uninit_sandbox() -> UninitializedSandbox { @@ -28,7 +27,7 @@ fn create_uninit_sandbox() -> UninitializedSandbox { } fn create_multiuse_sandbox() -> MultiUseSandbox { - create_uninit_sandbox().evolve(Noop::default()).unwrap() + create_uninit_sandbox().evolve().unwrap() } fn guest_call_benchmark(c: &mut Criterion) { @@ -65,7 +64,7 @@ fn guest_call_benchmark(c: &mut Criterion) { .unwrap(); let mut multiuse_sandbox: MultiUseSandbox = - uninitialized_sandbox.evolve(Noop::default()).unwrap(); + uninitialized_sandbox.evolve().unwrap(); b.iter(|| { multiuse_sandbox @@ -97,7 +96,7 @@ fn guest_call_benchmark_large_param(c: &mut Criterion) { Some(config), ) .unwrap(); - let mut sandbox = sandbox.evolve(Noop::default()).unwrap(); + let mut sandbox = sandbox.evolve().unwrap(); b.iter(|| { sandbox diff --git a/src/hyperlight_host/examples/func_ctx/main.rs b/src/hyperlight_host/examples/func_ctx/main.rs index 5161c10ee..b7a7e3142 100644 --- a/src/hyperlight_host/examples/func_ctx/main.rs +++ b/src/hyperlight_host/examples/func_ctx/main.rs @@ -15,7 +15,6 @@ limitations under the License. */ use hyperlight_host::sandbox::{MultiUseSandbox, UninitializedSandbox}; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; @@ -25,7 +24,7 @@ fn main() { let mut sbox1: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); - u_sbox.evolve(Noop::default()) + u_sbox.evolve() } .unwrap(); diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index 6c5876596..bb0511c86 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -19,7 +19,6 @@ use std::thread; use hyperlight_host::sandbox::SandboxConfiguration; #[cfg(gdb)] use hyperlight_host::sandbox::config::DebugInfo; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; /// Build a sandbox configuration that enables GDB debugging when the `gdb` feature is enabled. @@ -70,8 +69,8 @@ fn main() -> hyperlight_host::Result<()> { // Initialize sandboxes to be able to call host functions let mut multi_use_sandbox_dbg: MultiUseSandbox = - uninitialized_sandbox_dbg.evolve(Noop::default())?; - let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default())?; + uninitialized_sandbox_dbg.evolve()?; + let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve()?; // Call guest function let message = diff --git a/src/hyperlight_host/examples/hello-world/main.rs b/src/hyperlight_host/examples/hello-world/main.rs index 834ca09df..e8461954a 100644 --- a/src/hyperlight_host/examples/hello-world/main.rs +++ b/src/hyperlight_host/examples/hello-world/main.rs @@ -16,7 +16,6 @@ limitations under the License. #![allow(clippy::disallowed_macros)] use std::thread; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{MultiUseSandbox, UninitializedSandbox}; fn main() -> hyperlight_host::Result<()> { @@ -36,7 +35,7 @@ fn main() -> hyperlight_host::Result<()> { // Note: This function is unused, it's just here for demonstration purposes // Initialize sandbox to be able to call host functions - let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default())?; + let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve()?; // Call guest function let message = "Hello, World! I am executing inside of a VM :)\n".to_string(); diff --git a/src/hyperlight_host/examples/logging/main.rs b/src/hyperlight_host/examples/logging/main.rs index 0b4eb4e57..470441e72 100644 --- a/src/hyperlight_host/examples/logging/main.rs +++ b/src/hyperlight_host/examples/logging/main.rs @@ -19,8 +19,7 @@ extern crate hyperlight_host; use std::sync::{Arc, Barrier}; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; fn fn_writer(_msg: String) -> Result { @@ -46,10 +45,7 @@ fn main() -> Result<()> { usandbox.register_print(fn_writer)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; // Call a guest function 5 times to generate some log entries. for _ in 0..5 { @@ -79,10 +75,7 @@ fn main() -> Result<()> { UninitializedSandbox::new(GuestBinary::FilePath(hyperlight_guest_path.clone()), None)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; let interrupt_handle = multiuse_sandbox.interrupt_handle(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); diff --git a/src/hyperlight_host/examples/metrics/main.rs b/src/hyperlight_host/examples/metrics/main.rs index 9cc13e134..4328a3bfa 100644 --- a/src/hyperlight_host/examples/metrics/main.rs +++ b/src/hyperlight_host/examples/metrics/main.rs @@ -19,8 +19,7 @@ use std::sync::{Arc, Barrier}; use std::thread::{JoinHandle, spawn}; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; // Run this rust example with the flag --features "function_call_metrics" to enable more metrics to be emitted @@ -57,10 +56,7 @@ fn do_hyperlight_stuff() { usandbox.register_print(fn_writer)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op).expect("Failed to evolve sandbox"); + let mut multiuse_sandbox = usandbox.evolve().expect("Failed to evolve sandbox"); // Call a guest function 5 times to generate some metrics. for _ in 0..5 { @@ -91,10 +87,7 @@ fn do_hyperlight_stuff() { .expect("Failed to create UninitializedSandbox"); // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op).expect("Failed to evolve sandbox"); + let mut multiuse_sandbox = usandbox.evolve().expect("Failed to evolve sandbox"); let interrupt_handle = multiuse_sandbox.interrupt_handle(); const NUM_CALLS: i32 = 5; diff --git a/src/hyperlight_host/examples/tracing-chrome/main.rs b/src/hyperlight_host/examples/tracing-chrome/main.rs index ba08a1ebc..0b52ebb9c 100644 --- a/src/hyperlight_host/examples/tracing-chrome/main.rs +++ b/src/hyperlight_host/examples/tracing-chrome/main.rs @@ -15,8 +15,7 @@ limitations under the License. */ #![allow(clippy::disallowed_macros)] use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; use tracing_chrome::ChromeLayerBuilder; use tracing_subscriber::prelude::*; @@ -34,7 +33,7 @@ fn main() -> Result<()> { let usandbox = UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)?; let mut sbox = usandbox - .evolve(Noop::::default()) + .evolve() .unwrap(); // do the function call diff --git a/src/hyperlight_host/examples/tracing-otlp/main.rs b/src/hyperlight_host/examples/tracing-otlp/main.rs index c6362c5de..69d318c1f 100644 --- a/src/hyperlight_host/examples/tracing-otlp/main.rs +++ b/src/hyperlight_host/examples/tracing-otlp/main.rs @@ -27,8 +27,7 @@ use std::sync::{Arc, Barrier, Mutex}; use std::thread::{JoinHandle, spawn}; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result as HyperlightResult}; +use hyperlight_host::{GuestBinary, Result as HyperlightResult}; use hyperlight_testing::simple_guest_as_string; use opentelemetry::trace::TracerProvider; use opentelemetry::{KeyValue, global}; @@ -132,10 +131,7 @@ fn run_example(wait_input: bool) -> HyperlightResult<()> { usandbox.register_print(fn_writer)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; // Call a guest function 5 times to generate some log entries. for _ in 0..5 { diff --git a/src/hyperlight_host/examples/tracing-tracy/main.rs b/src/hyperlight_host/examples/tracing-tracy/main.rs index 68cfbcb4c..bdf1accc9 100644 --- a/src/hyperlight_host/examples/tracing-tracy/main.rs +++ b/src/hyperlight_host/examples/tracing-tracy/main.rs @@ -15,8 +15,7 @@ limitations under the License. */ #![allow(clippy::disallowed_macros)] use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; use tracing_subscriber::EnvFilter; use tracing_subscriber::layer::SubscriberExt; @@ -40,7 +39,7 @@ fn main() -> Result<()> { let usandbox = UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)?; let mut sbox = usandbox - .evolve(Noop::::default()) + .evolve() .unwrap(); // do the function call diff --git a/src/hyperlight_host/examples/tracing/main.rs b/src/hyperlight_host/examples/tracing/main.rs index 4e981b5e0..66020dcfa 100644 --- a/src/hyperlight_host/examples/tracing/main.rs +++ b/src/hyperlight_host/examples/tracing/main.rs @@ -20,8 +20,7 @@ use std::sync::{Arc, Barrier}; use std::thread::{JoinHandle, spawn}; use hyperlight_host::sandbox::uninitialized::UninitializedSandbox; -use hyperlight_host::sandbox_state::transition::Noop; -use hyperlight_host::{GuestBinary, MultiUseSandbox, Result}; +use hyperlight_host::{GuestBinary, Result}; use hyperlight_testing::simple_guest_as_string; use tracing_forest::ForestLayer; use tracing_subscriber::layer::SubscriberExt; @@ -74,10 +73,7 @@ fn run_example() -> Result<()> { usandbox.register_print(fn_writer)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; // Call a guest function 5 times to generate some log entries. for _ in 0..5 { @@ -106,10 +102,7 @@ fn run_example() -> Result<()> { UninitializedSandbox::new(GuestBinary::FilePath(hyperlight_guest_path.clone()), None)?; // Initialize the sandbox. - - let no_op = Noop::::default(); - - let mut multiuse_sandbox = usandbox.evolve(no_op)?; + let mut multiuse_sandbox = usandbox.evolve()?; let interrupt_handle = multiuse_sandbox.interrupt_handle(); // Call a function that gets cancelled by the host function 5 times to generate some log entries. diff --git a/src/hyperlight_host/src/metrics/mod.rs b/src/hyperlight_host/src/metrics/mod.rs index bc34b38f7..a2f4026e5 100644 --- a/src/hyperlight_host/src/metrics/mod.rs +++ b/src/hyperlight_host/src/metrics/mod.rs @@ -93,7 +93,6 @@ mod tests { use metrics_util::CompositeKey; use super::*; - use crate::sandbox_state::transition::Noop; use crate::{GuestBinary, UninitializedSandbox}; #[test] @@ -107,7 +106,7 @@ mod tests { ) .unwrap(); - let mut multi = uninit.evolve(Noop::default()).unwrap(); + let mut multi = uninit.evolve().unwrap(); let interrupt_handle = multi.interrupt_handle(); // interrupt the guest function call to "Spin" after 1 second diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 5d6655f01..32a0b74a1 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -307,7 +307,6 @@ mod tests { #[cfg(target_os = "linux")] use crate::mem::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, SharedMemory as _}; use crate::sandbox::{Callable, SandboxConfiguration}; - use crate::sandbox_state::transition::Noop; use crate::{GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox}; // Tests to ensure that many (1000) function calls can be made in a call context with a small stack (1K) and heap(14K). @@ -321,7 +320,7 @@ mod tests { let mut sbox1: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), Some(cfg)).unwrap(); - u_sbox.evolve(Noop::default()) + u_sbox.evolve() } .unwrap(); @@ -332,7 +331,7 @@ mod tests { let mut sbox2: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), Some(cfg)).unwrap(); - u_sbox.evolve(Noop::default()) + u_sbox.evolve() } .unwrap(); @@ -352,7 +351,7 @@ mod tests { let mut sbox: MultiUseSandbox = { let path = simple_guest_as_string().unwrap(); let u_sbox = UninitializedSandbox::new(GuestBinary::FilePath(path), None).unwrap(); - u_sbox.evolve(Noop::default()) + u_sbox.evolve() } .unwrap(); @@ -389,7 +388,7 @@ mod tests { usbox.register("MakeGetpidSyscall", make_get_pid_syscall)?; - let mut sbox: MultiUseSandbox = usbox.evolve(Noop::default())?; + let mut sbox: MultiUseSandbox = usbox.evolve()?; let res: Result = sbox.call_guest_function_by_name("ViolateSeccompFilters", ()); @@ -425,7 +424,7 @@ mod tests { )?; // ^^^ note, we are allowing SYS_getpid - let mut sbox: MultiUseSandbox = usbox.evolve(Noop::default())?; + let mut sbox: MultiUseSandbox = usbox.evolve()?; let res: Result = sbox.call_guest_function_by_name("ViolateSeccompFilters", ()); @@ -479,7 +478,7 @@ mod tests { .unwrap(); ubox.register("Openat_Hostfunc", make_openat_syscall)?; - let mut sbox = ubox.evolve(Noop::default()).unwrap(); + let mut sbox = ubox.evolve().unwrap(); let host_func_result = sbox .call_guest_function_by_name::( "CallGivenParamlessHostFuncThatReturnsI64", @@ -509,7 +508,7 @@ mod tests { make_openat_syscall, [libc::SYS_openat], )?; - let mut sbox = ubox.evolve(Noop::default()).unwrap(); + let mut sbox = ubox.evolve().unwrap(); let host_func_result = sbox .call_guest_function_by_name::( "CallGivenParamlessHostFuncThatReturnsI64", @@ -532,7 +531,7 @@ mod tests { ) .unwrap(); - let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve(Noop::default()).unwrap(); + let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve().unwrap(); let res: Result<()> = multi_use_sandbox.call_guest_function_by_name("TriggerException", ()); @@ -573,7 +572,7 @@ mod tests { .unwrap(); let mut multi_use_sandbox: MultiUseSandbox = - usbox.evolve(Noop::default()).unwrap(); + usbox.evolve().unwrap(); let res: i32 = multi_use_sandbox .call_guest_function_by_name("GetStatic", ()) @@ -601,7 +600,7 @@ mod tests { None, ) .unwrap() - .evolve(Noop::default()) + .evolve() .unwrap(); let expected = b"hello world"; diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 529fc4ffc..206fb30ad 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -104,7 +104,6 @@ mod tests { use hyperlight_testing::simple_guest_as_string; use crate::sandbox::uninitialized::GuestBinary; - use crate::sandbox_state::transition::Noop; use crate::{MultiUseSandbox, UninitializedSandbox, new_error}; #[test] @@ -166,7 +165,7 @@ mod tests { .unwrap(); let sandbox = uninitialized_sandbox - .evolve(Noop::default()) + .evolve() .unwrap_or_else(|_| { panic!("Failed to initialize UninitializedSandbox thread {}", i) }); diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index 1dcb8e7ef..d5c69d167 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -34,7 +34,6 @@ use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags} use crate::mem::mgr::{STACK_COOKIE_LEN, SandboxMemoryManager}; use crate::mem::shared_mem::ExclusiveSharedMemory; use crate::sandbox::SandboxConfiguration; -use crate::sandbox_state::transition::Noop; use crate::{MultiUseSandbox, Result, log_then_return, new_error}; #[cfg(all(target_os = "linux", feature = "seccomp"))] @@ -112,7 +111,7 @@ impl crate::sandbox_state::sandbox::Sandbox for UninitializedSandbox { impl UninitializedSandbox { /// Evolve `self` to a `MultiUseSandbox` without any additional metadata. #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] - pub fn evolve(self, _: Noop) -> Result { + pub fn evolve(self) -> Result { evolve_impl_multi_use(self) } } @@ -426,7 +425,6 @@ mod tests { use crate::sandbox::SandboxConfiguration; use crate::sandbox::uninitialized::{GuestBinary, GuestEnvironment}; - use crate::sandbox_state::transition::Noop; use crate::{MultiUseSandbox, Result, UninitializedSandbox, new_error}; #[test] @@ -437,7 +435,7 @@ mod tests { GuestEnvironment::new(GuestBinary::FilePath(binary_path.clone()), Some(&buffer)); let uninitialized_sandbox = UninitializedSandbox::new(guest_env, None).unwrap(); - let mut sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default()).unwrap(); + let mut sandbox: MultiUseSandbox = uninitialized_sandbox.evolve().unwrap(); let res = sandbox .call_guest_function_by_name::>("ReadFromUserMemory", (4u64, buffer.to_vec())) @@ -481,7 +479,7 @@ mod tests { // Get a Sandbox from an uninitialized sandbox without a call back function - let _sandbox: MultiUseSandbox = uninitialized_sandbox.evolve(Noop::default()).unwrap(); + let _sandbox: MultiUseSandbox = uninitialized_sandbox.evolve().unwrap(); // Test with a valid guest binary buffer @@ -529,7 +527,7 @@ mod tests { usbox.register("test0", |arg: i32| Ok(arg + 1)).unwrap(); - let sandbox: Result = usbox.evolve(Noop::default()); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -554,7 +552,7 @@ mod tests { usbox.register("test1", |a: i32, b: i32| Ok(a + b)).unwrap(); - let sandbox: Result = usbox.evolve(Noop::default()); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -587,7 +585,7 @@ mod tests { }) .unwrap(); - let sandbox: Result = usbox.evolve(Noop::default()); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -605,7 +603,7 @@ mod tests { // calling a function that doesn't exist { let usbox = uninitialized_sandbox(); - let sandbox: Result = usbox.evolve(Noop::default()); + let sandbox: Result = usbox.evolve(); assert!(sandbox.is_ok()); let sandbox = sandbox.unwrap(); @@ -829,7 +827,7 @@ mod tests { .unwrap(); let sandbox = uninitialized_sandbox - .evolve(Noop::default()) + .evolve() .unwrap_or_else(|_| { panic!("Failed to initialize UninitializedSandbox thread {}", i) }); @@ -1120,7 +1118,7 @@ mod tests { ); res.unwrap() }; - let _: Result = sbox.evolve(Noop::default()); + let _: Result = sbox.evolve(); let num_calls = TEST_LOGGER.num_log_calls(); diff --git a/src/hyperlight_host/src/sandbox_state/mod.rs b/src/hyperlight_host/src/sandbox_state/mod.rs index 474cad72a..e0c4b1b2d 100644 --- a/src/hyperlight_host/src/sandbox_state/mod.rs +++ b/src/hyperlight_host/src/sandbox_state/mod.rs @@ -17,5 +17,3 @@ limitations under the License. /// The standardized `Sandbox` trait and the ways it ban be transitioned /// to a different `Sandbox` trait pub mod sandbox; -/// Metadata about transitions between `Sandbox` states -pub mod transition; diff --git a/src/hyperlight_host/src/sandbox_state/transition.rs b/src/hyperlight_host/src/sandbox_state/transition.rs deleted file mode 100644 index 1c918f06a..000000000 --- a/src/hyperlight_host/src/sandbox_state/transition.rs +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use std::marker::PhantomData; - -use super::sandbox::Sandbox; - -/// Transition metadata that contains and does nothing. `Noop` is a -/// placeholder when you want to implement an `EvolvableSandbox` -/// that needs no additional metadata to succeed. -/// -/// Construct one of these by using the `default()` method. -pub struct Noop { - cur_ph: PhantomData, - next_ph: PhantomData, -} - -impl Default for Noop { - fn default() -> Self { - Self { - cur_ph: PhantomData, - next_ph: PhantomData, - } - } -} diff --git a/src/hyperlight_host/tests/common/mod.rs b/src/hyperlight_host/tests/common/mod.rs index 75d7c27be..5ff8cc3e0 100644 --- a/src/hyperlight_host/tests/common/mod.rs +++ b/src/hyperlight_host/tests/common/mod.rs @@ -15,7 +15,6 @@ limitations under the License. */ use hyperlight_host::func::HostFunction; use hyperlight_host::sandbox::SandboxConfiguration; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, MultiUseSandbox, Result, UninitializedSandbox}; use hyperlight_testing::{ c_callback_guest_as_string, c_simple_guest_as_string, callback_guest_as_string, @@ -59,7 +58,7 @@ pub fn get_simpleguest_sandboxes( if let Some(writer) = writer.clone() { sandbox.register_print(writer).unwrap(); } - sandbox.evolve(Noop::default()).unwrap() + sandbox.evolve().unwrap() }) .collect() } diff --git a/src/hyperlight_host/tests/integration_test.rs b/src/hyperlight_host/tests/integration_test.rs index c7ab9329a..967d93c53 100644 --- a/src/hyperlight_host/tests/integration_test.rs +++ b/src/hyperlight_host/tests/integration_test.rs @@ -22,7 +22,6 @@ use std::time::Duration; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::mem::PAGE_SIZE; use hyperlight_host::sandbox::SandboxConfiguration; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{GuestBinary, HyperlightError, MultiUseSandbox, UninitializedSandbox}; use hyperlight_testing::simplelogger::{LOGGER, SimpleLogger}; use hyperlight_testing::{ @@ -60,7 +59,7 @@ fn interrupt_host_call() { .register_with_extra_allowed_syscalls("Spin", spin, vec![libc::SYS_clock_nanosleep]) .unwrap(); - let mut sandbox: MultiUseSandbox = usbox.evolve(Noop::default()).unwrap(); + let mut sandbox: MultiUseSandbox = usbox.evolve().unwrap(); let interrupt_handle = sandbox.interrupt_handle(); assert!(!interrupt_handle.dropped()); // not yet dropped @@ -82,7 +81,7 @@ fn interrupt_host_call() { /// Makes sure a running guest call can be interrupted by the host #[test] fn interrupt_in_progress_guest_call() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); let interrupt_handle = sbox1.interrupt_handle(); @@ -117,7 +116,7 @@ fn interrupt_in_progress_guest_call() { /// Makes sure interrupting a vm before the guest call has started also prevents the guest call from being executed #[test] fn interrupt_guest_call_in_advance() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); let interrupt_handle = sbox1.interrupt_handle(); @@ -159,9 +158,9 @@ fn interrupt_guest_call_in_advance() { /// all possible interleavings, but can hopefully increases confidence somewhat. #[test] fn interrupt_same_thread() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox3: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox3: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); @@ -201,9 +200,9 @@ fn interrupt_same_thread() { /// Same test as above but with no per-iteration barrier, to get more possible interleavings. #[test] fn interrupt_same_thread_no_barrier() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox3: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox3: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let barrier = Arc::new(Barrier::new(2)); let barrier2 = barrier.clone(); @@ -247,8 +246,8 @@ fn interrupt_same_thread_no_barrier() { // and that anther sandbox on the original thread does not get incorrectly killed #[test] fn interrupt_moved_sandbox() { - let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); - let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); + let mut sbox2: MultiUseSandbox = new_uninit_rust().unwrap().evolve().unwrap(); let interrupt_handle = sbox1.interrupt_handle(); let interrupt_handle2 = sbox2.interrupt_handle(); @@ -299,7 +298,7 @@ fn interrupt_custom_signal_no_and_retry_delay() { Some(config), ) .unwrap() - .evolve(Noop::default()) + .evolve() .unwrap(); let interrupt_handle = sbox1.interrupt_handle(); @@ -339,7 +338,7 @@ fn interrupt_spamming_host_call() { // do nothing }) .unwrap(); - let mut sbox1: MultiUseSandbox = uninit.evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = uninit.evolve().unwrap(); let interrupt_handle = sbox1.interrupt_handle(); @@ -368,7 +367,7 @@ fn print_four_args_c_guest() { let path = c_simple_guest_as_string().unwrap(); let guest_path = GuestBinary::FilePath(path); let uninit = UninitializedSandbox::new(guest_path, None); - let mut sbox1 = uninit.unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = uninit.unwrap().evolve().unwrap(); let res = sbox1.call_guest_function_by_name::( "PrintFourArgs", @@ -381,7 +380,7 @@ fn print_four_args_c_guest() { // Checks that guest can abort with a specific code. #[test] fn guest_abort() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let error_code: u8 = 13; // this is arbitrary let res = sbox1 .call_guest_function_by_name::<()>("GuestAbortWithCode", error_code as i32) @@ -394,7 +393,7 @@ fn guest_abort() { #[test] fn guest_abort_with_context1() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let res = sbox1 .call_guest_function_by_name::<()>("GuestAbortWithMessage", (25_i32, "Oh no".to_string())) @@ -407,7 +406,7 @@ fn guest_abort_with_context1() { #[test] fn guest_abort_with_context2() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); // The buffer size for the panic context is 1024 bytes. // This test will see what happens if the panic message is longer than that @@ -461,7 +460,7 @@ fn guest_abort_c_guest() { let path = c_simple_guest_as_string().unwrap(); let guest_path = GuestBinary::FilePath(path); let uninit = UninitializedSandbox::new(guest_path, None); - let mut sbox1 = uninit.unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = uninit.unwrap().evolve().unwrap(); let res = sbox1 .call_guest_function_by_name::<()>( @@ -478,7 +477,7 @@ fn guest_abort_c_guest() { #[test] fn guest_panic() { // this test is rust-specific - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let res = sbox1 .call_guest_function_by_name::<()>("guest_panic", "Error... error...".to_string()) @@ -492,7 +491,7 @@ fn guest_panic() { #[test] fn guest_malloc() { // this test is rust-only - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let size_to_allocate = 2000_i32; sbox1 @@ -502,7 +501,7 @@ fn guest_malloc() { #[test] fn guest_allocate_vec() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let size_to_allocate = 2000_i32; @@ -519,7 +518,7 @@ fn guest_allocate_vec() { // checks that malloc failures are captured correctly #[test] fn guest_malloc_abort() { - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let size = 20000000_i32; // some big number that should fail when allocated @@ -543,7 +542,7 @@ fn guest_malloc_abort() { Some(cfg), ) .unwrap(); - let mut sbox2 = uninit.evolve(Noop::default()).unwrap(); + let mut sbox2 = uninit.evolve().unwrap(); let res = sbox2.call_guest_function_by_name::( "CallMalloc", // uses the rust allocator to allocate a vector on heap @@ -563,7 +562,7 @@ fn dynamic_stack_allocate_c_guest() { let path = c_simple_guest_as_string().unwrap(); let guest_path = GuestBinary::FilePath(path); let uninit = UninitializedSandbox::new(guest_path, None); - let mut sbox1: MultiUseSandbox = uninit.unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1: MultiUseSandbox = uninit.unwrap().evolve().unwrap(); let res: i32 = sbox1 .call_guest_function_by_name("StackAllocate", 100_i32) @@ -579,7 +578,7 @@ fn dynamic_stack_allocate_c_guest() { // checks that a small buffer on stack works #[test] fn static_stack_allocate() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let res: i32 = sbox1.call_guest_function_by_name("SmallVar", ()).unwrap(); assert_eq!(res, 1024); @@ -588,7 +587,7 @@ fn static_stack_allocate() { // checks that a huge buffer on stack fails with stackoverflow #[test] fn static_stack_allocate_overflow() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let res = sbox1 .call_guest_function_by_name::("LargeVar", ()) .unwrap_err(); @@ -598,7 +597,7 @@ fn static_stack_allocate_overflow() { // checks that a recursive function with stack allocation works, (that chkstk can be called without overflowing) #[test] fn recursive_stack_allocate() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let iterations = 1_i32; @@ -628,7 +627,7 @@ fn guard_page_check() { for offset in offsets_from_page_guard_start { // we have to create a sandbox each iteration because can't reuse after MMIO error in release mode - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let result = sbox1.call_guest_function_by_name::("test_write_raw_ptr", offset); if guard_range.contains(&offset) { // should have failed @@ -645,7 +644,7 @@ fn guard_page_check() { #[test] fn guard_page_check_2() { // this test is rust-guest only - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let result = sbox1 .call_guest_function_by_name::<()>("InfiniteRecursion", ()) @@ -655,7 +654,7 @@ fn guard_page_check_2() { #[test] fn execute_on_stack() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let result = sbox1 .call_guest_function_by_name::("ExecuteOnStack", ()) @@ -671,7 +670,7 @@ fn execute_on_stack() { #[test] #[ignore] // ran from Justfile because requires feature "executable_heap" fn execute_on_heap() { - let mut sbox1 = new_uninit_rust().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit_rust().unwrap().evolve().unwrap(); let result = sbox1.call_guest_function_by_name::("ExecuteOnHeap", ()); println!("{:#?}", result); @@ -690,7 +689,7 @@ fn execute_on_heap() { // checks that a recursive function with stack allocation eventually fails with stackoverflow #[test] fn recursive_stack_allocate_overflow() { - let mut sbox1 = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sbox1 = new_uninit().unwrap().evolve().unwrap(); let iterations = 10_i32; @@ -765,7 +764,7 @@ fn log_test_messages(levelfilter: Option) { sbox.set_max_guest_log_level(levelfilter); } - let mut sbox1 = sbox.evolve(Noop::default()).unwrap(); + let mut sbox1 = sbox.evolve().unwrap(); let message = format!("Hello from log_message level {}", level as i32); sbox1 diff --git a/src/hyperlight_host/tests/sandbox_host_tests.rs b/src/hyperlight_host/tests/sandbox_host_tests.rs index 49697a0ed..7ca0ba5dc 100644 --- a/src/hyperlight_host/tests/sandbox_host_tests.rs +++ b/src/hyperlight_host/tests/sandbox_host_tests.rs @@ -20,7 +20,6 @@ use std::sync::{Arc, Mutex}; use common::new_uninit; use hyperlight_host::sandbox::{Callable, SandboxConfiguration}; -use hyperlight_host::sandbox_state::transition::Noop; use hyperlight_host::{ GuestBinary, HyperlightError, MultiUseSandbox, Result, UninitializedSandbox, new_error, }; @@ -84,7 +83,7 @@ fn float_roundtrip() { f32::NAN, -f32::NAN, ]; - let mut sandbox: MultiUseSandbox = new_uninit().unwrap().evolve(Noop::default()).unwrap(); + let mut sandbox: MultiUseSandbox = new_uninit().unwrap().evolve().unwrap(); for f in doubles.iter() { let res: f64 = sandbox .call_guest_function_by_name("EchoDouble", *f) @@ -331,7 +330,7 @@ fn callback_test_helper() -> Result<()> { })?; // call guest function that calls host function - let mut init_sandbox: MultiUseSandbox = sandbox.evolve(Noop::default())?; + let mut init_sandbox: MultiUseSandbox = sandbox.evolve()?; let msg = "Hello world"; init_sandbox.call_guest_function_by_name::("GuestMethod1", msg.to_string())?; @@ -373,7 +372,7 @@ fn host_function_error() -> Result<()> { })?; // call guest function that calls host function - let mut init_sandbox: MultiUseSandbox = sandbox.evolve(Noop::default())?; + let mut init_sandbox: MultiUseSandbox = sandbox.evolve()?; let msg = "Hello world"; let res = init_sandbox .call_guest_function_by_name::("GuestMethod1", msg.to_string()) From 57b83c5465aa3b3fc7f0068570fc7a229160dfcc Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Tue, 8 Jul 2025 15:28:06 +0100 Subject: [PATCH 13/18] remove automatic snapshot stack Signed-off-by: Jorge Prendes --- src/hyperlight_host/src/mem/mgr.rs | 41 ------------------- .../src/sandbox/initialized_multi_use.rs | 10 ++--- .../src/sandbox/uninitialized_evolve.rs | 11 +++-- 3 files changed, 8 insertions(+), 54 deletions(-) diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index 380871be7..e5d327963 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -15,7 +15,6 @@ limitations under the License. */ use std::cmp::Ordering; -use std::sync::{Arc, Mutex}; use hyperlight_common::flatbuffer_wrappers::function_call::{ FunctionCall, validate_guest_function_call_buffer, @@ -34,7 +33,6 @@ use super::ptr::{GuestPtr, RawPtr}; use super::ptr_offset::Offset; use super::shared_mem::{ExclusiveSharedMemory, GuestSharedMemory, HostSharedMemory, SharedMemory}; use super::shared_mem_snapshot::SharedMemorySnapshot; -use crate::HyperlightError::NoMemorySnapshot; use crate::sandbox::SandboxConfiguration; use crate::sandbox::uninitialized::GuestBlob; use crate::{Result, log_then_return, new_error}; @@ -75,9 +73,6 @@ pub(crate) struct SandboxMemoryManager { pub(crate) entrypoint_offset: Offset, /// How many memory regions were mapped after sandbox creation pub(crate) mapped_rgns: u64, - /// A vector of memory snapshots that can be used to save and restore the state of the memory - /// This is used by the Rust Sandbox implementation (rather than the mem_snapshot field above which only exists to support current C API) - snapshots: Arc>>, } impl SandboxMemoryManager @@ -98,7 +93,6 @@ where load_addr, entrypoint_offset, mapped_rgns: 0, - snapshots: Arc::new(Mutex::new(Vec::new())), } } @@ -288,39 +282,6 @@ where Ok(old_rgns - self.mapped_rgns) } - /// this function will create a memory snapshot and push it onto the stack of snapshots - /// It should be used when you want to save the state of the memory, for example, when evolving a sandbox to a new state - pub(crate) fn push_state(&mut self) -> Result<()> { - let snapshot = self.snapshot()?; - self.snapshots - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - .push(snapshot); - Ok(()) - } - - /// this function restores a memory snapshot from the last snapshot in the list but does not pop the snapshot - /// off the stack - /// It should be used when you want to restore the state of the memory to a previous state but still want to - /// retain that state, for example after calling a function in the guest - /// - /// Returns the number of memory regions mapped into the sandbox - /// that need to be unmapped in order for the restore to be - /// completed. - pub(crate) fn restore_state_from_last_snapshot(&mut self) -> Result { - let snapshots = self - .snapshots - .try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?; - let last = snapshots.last(); - let Some(snapshot) = last else { - log_then_return!(NoMemorySnapshot); - }; - let old_rgns = self.mapped_rgns; - self.mapped_rgns = snapshot.restore_from_snapshot(&mut self.shared_mem)?; - Ok(old_rgns - self.mapped_rgns) - } - /// Sets `addr` to the correct offset in the memory referenced by /// `shared_mem` to indicate the address of the outb pointer and context /// for calling outb function @@ -446,7 +407,6 @@ impl SandboxMemoryManager { load_addr: self.load_addr.clone(), entrypoint_offset: self.entrypoint_offset, mapped_rgns: 0, - snapshots: Arc::new(Mutex::new(Vec::new())), }, SandboxMemoryManager { shared_mem: gshm, @@ -454,7 +414,6 @@ impl SandboxMemoryManager { load_addr: self.load_addr.clone(), entrypoint_offset: self.entrypoint_offset, mapped_rgns: 0, - snapshots: Arc::new(Mutex::new(Vec::new())), }, ) } diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 32a0b74a1..3ca5c9514 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -124,9 +124,7 @@ impl MultiUseSandbox { Output::TYPE, args.into_value(), ); - let ret = Output::from_value(ret?); - self.mem_mgr.unwrap_mgr_mut().push_state().unwrap(); - ret + Output::from_value(ret?) }) } @@ -209,13 +207,11 @@ impl MultiUseSandbox { args: Vec, ) -> Result { maybe_time_and_emit_guest_call(func_name, || { - let ret = self.call_guest_function_by_name_no_reset(func_name, ret_type, args); - self.mem_mgr.unwrap_mgr_mut().push_state()?; - ret + self.call_guest_function_by_name_no_reset(func_name, ret_type, args) }) } - pub(crate) fn call_guest_function_by_name_no_reset( + fn call_guest_function_by_name_no_reset( &mut self, function_name: &str, return_type: ReturnType, diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index a37f747e2..30c92fd7c 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -129,19 +129,18 @@ where pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result { evolve_impl( u_sbox, - |hf, mut hshm, vm, out_hdl, mem_hdl, dispatch_ptr| { - { - hshm.as_mut().push_state()?; - } + |hf, hshm, vm, out_hdl, mem_hdl, dispatch_ptr| { + #[cfg(gdb)] + let dbg_mem_wrapper = dbg_mem_access_handler_wrapper(hshm.clone()); Ok(MultiUseSandbox::from_uninit( hf, - hshm.clone(), + hshm, vm, out_hdl, mem_hdl, dispatch_ptr, #[cfg(gdb)] - dbg_mem_access_handler_wrapper(hshm), + dbg_mem_wrapper, )) }, ) From c1a3e898b03f2925ec1416f905f95fdcc27b6ed0 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Tue, 8 Jul 2025 15:47:44 +0100 Subject: [PATCH 14/18] Remove Sandbox trait Signed-off-by: Jorge Prendes --- src/hyperlight_host/src/lib.rs | 3 - .../src/sandbox/initialized_multi_use.rs | 9 +-- .../src/sandbox/uninitialized.rs | 22 +------ .../src/sandbox/uninitialized_evolve.rs | 3 +- src/hyperlight_host/src/sandbox_state/mod.rs | 19 ------ .../src/sandbox_state/sandbox.rs | 61 ------------------- 6 files changed, 3 insertions(+), 114 deletions(-) delete mode 100644 src/hyperlight_host/src/sandbox_state/mod.rs delete mode 100644 src/hyperlight_host/src/sandbox_state/sandbox.rs diff --git a/src/hyperlight_host/src/lib.rs b/src/hyperlight_host/src/lib.rs index 5eb5c165a..6e5e67816 100644 --- a/src/hyperlight_host/src/lib.rs +++ b/src/hyperlight_host/src/lib.rs @@ -58,9 +58,6 @@ pub mod metrics; /// outside this file. Types from this module needed for public consumption are /// re-exported below. pub mod sandbox; -/// `trait`s and other functionality for dealing with defining sandbox -/// states and moving between them -pub mod sandbox_state; #[cfg(all(feature = "seccomp", target_os = "linux"))] pub(crate) mod seccomp; /// Signal handling for Linux diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 3ca5c9514..72157471f 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -42,7 +42,6 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags}; use crate::mem::ptr::RawPtr; use crate::mem::shared_mem::HostSharedMemory; use crate::metrics::maybe_time_and_emit_guest_call; -use crate::sandbox_state::sandbox::Sandbox; use crate::{HyperlightError, Result, log_then_return}; /// A sandbox that supports being used Multiple times. @@ -241,7 +240,7 @@ impl MultiUseSandbox { self.dbg_mem_access_fn.clone(), )?; - self.check_stack_guard()?; + self.mem_mgr.check_stack_guard()?; check_for_guest_error(self.get_mgr_wrapper_mut())?; self.get_mgr_wrapper_mut() @@ -277,12 +276,6 @@ impl WrapperGetter for MultiUseSandbox { } } -impl Sandbox for MultiUseSandbox { - fn check_stack_guard(&self) -> Result { - self.mem_mgr.check_stack_guard() - } -} - impl std::fmt::Debug for MultiUseSandbox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MultiUseSandbox") diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index d5c69d167..8271b54d8 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -34,7 +34,7 @@ use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags} use crate::mem::mgr::{STACK_COOKIE_LEN, SandboxMemoryManager}; use crate::mem::shared_mem::ExclusiveSharedMemory; use crate::sandbox::SandboxConfiguration; -use crate::{MultiUseSandbox, Result, log_then_return, new_error}; +use crate::{MultiUseSandbox, Result, new_error}; #[cfg(all(target_os = "linux", feature = "seccomp"))] const EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC: &[super::ExtraAllowedSyscall] = &[ @@ -80,18 +80,6 @@ pub struct UninitializedSandbox { pub(crate) rt_cfg: SandboxRuntimeConfig, } -impl crate::sandbox_state::sandbox::UninitializedSandbox for UninitializedSandbox { - #[instrument(skip_all, parent = Span::current(), level = "Trace")] - fn get_uninitialized_sandbox(&self) -> &crate::sandbox::UninitializedSandbox { - self - } - - #[instrument(skip_all, parent = Span::current(), level = "Trace")] - fn get_uninitialized_sandbox_mut(&mut self) -> &mut crate::sandbox::UninitializedSandbox { - self - } -} - impl Debug for UninitializedSandbox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("UninitializedSandbox") @@ -100,14 +88,6 @@ impl Debug for UninitializedSandbox { } } -impl crate::sandbox_state::sandbox::Sandbox for UninitializedSandbox { - fn check_stack_guard(&self) -> Result { - log_then_return!( - "Checking the stack cookie before the sandbox is initialized is unsupported" - ); - } -} - impl UninitializedSandbox { /// Evolve `self` to a `MultiUseSandbox` without any additional metadata. #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 30c92fd7c..55da42434 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -41,7 +41,6 @@ use crate::sandbox::host_funcs::FunctionRegistry; use crate::sandbox::mem_access::mem_access_handler_wrapper; use crate::sandbox::outb::outb_handler_wrapper; use crate::sandbox::{HostSharedMemory, MemMgrWrapper}; -use crate::sandbox_state::sandbox::Sandbox; #[cfg(target_os = "linux")] use crate::signal_handlers::setup_signal_handlers; use crate::{MultiUseSandbox, Result, UninitializedSandbox, log_then_return, new_error}; @@ -58,7 +57,7 @@ use crate::{MultiUseSandbox, Result, UninitializedSandbox, log_then_return, new_ /// If this doesn't make sense, and you want to change this type, /// please reach out to a Hyperlight developer before making the change. #[instrument(err(Debug), skip_all, , parent = Span::current(), level = "Trace")] -fn evolve_impl( +fn evolve_impl( u_sbox: UninitializedSandbox, transform: TransformFunc, ) -> Result diff --git a/src/hyperlight_host/src/sandbox_state/mod.rs b/src/hyperlight_host/src/sandbox_state/mod.rs deleted file mode 100644 index e0c4b1b2d..000000000 --- a/src/hyperlight_host/src/sandbox_state/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/// The standardized `Sandbox` trait and the ways it ban be transitioned -/// to a different `Sandbox` trait -pub mod sandbox; diff --git a/src/hyperlight_host/src/sandbox_state/sandbox.rs b/src/hyperlight_host/src/sandbox_state/sandbox.rs deleted file mode 100644 index b88738835..000000000 --- a/src/hyperlight_host/src/sandbox_state/sandbox.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2025 The Hyperlight Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -use std::fmt::Debug; - -use tracing::{Span, instrument}; - -use crate::{Result, new_error}; - -/// The minimal functionality of a Hyperlight sandbox. Most of the types -/// and operations within this crate require `Sandbox` implementations. -/// -/// `Sandbox`es include the notion of an ordering in a state machine. -/// For example, a given `Sandbox` implementation may be the root node -/// in the state machine to which it belongs, and it may know how to "evolve" -/// into a next state. That "next state" may in turn know how to roll back -/// to the root node. -/// -/// TODO: fix this comment, it is not accurate anymore -pub trait Sandbox: Sized + Debug { - /// Check to ensure the current stack cookie matches the one that - /// was selected when the stack was constructed. - /// - /// Return an `Err` if there was an error inspecting the stack, `Ok(false)` - /// if there was no such error but the stack guard doesn't match, and - /// `Ok(true)` in the same situation where the stack guard does match. - /// - - // NOTE: this is only needed for UninitializedSandbox and MultiUseSandbox - // Those are the only types that need implement this trait - // The default implementation is provided so that types that implement Sandbox (e.g. JSSandbox) but do not need to implement this trait do not need to provide an implementation - #[instrument(skip_all, parent = Span::current(), level= "Trace")] - fn check_stack_guard(&self) -> Result { - Err(new_error!( - "check_stack_guard not implemented for this type" - )) - } -} - -/// A utility trait to recognize a Sandbox that has not yet been initialized. -/// It allows retrieval of a strongly typed UninitializedSandbox. -pub trait UninitializedSandbox: Sandbox { - /// Retrieves reference to strongly typed `UninitializedSandbox` - fn get_uninitialized_sandbox(&self) -> &crate::sandbox::UninitializedSandbox; - - /// Retrieves mutable reference to strongly typed `UninitializedSandbox` - fn get_uninitialized_sandbox_mut(&mut self) -> &mut crate::sandbox::UninitializedSandbox; -} From 98492d401318e8830c492b8f82c0d1a8e4b641b1 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Tue, 8 Jul 2025 16:31:03 +0100 Subject: [PATCH 15/18] fix formatting Signed-off-by: Jorge Prendes --- src/hyperlight_host/benches/benchmarks.rs | 3 +- .../examples/guest-debugging/main.rs | 3 +- .../examples/tracing-chrome/main.rs | 4 +-- .../examples/tracing-tracy/main.rs | 4 +-- .../src/sandbox/initialized_multi_use.rs | 20 ++++++++----- src/hyperlight_host/src/sandbox/mod.rs | 8 ++--- .../src/sandbox/uninitialized.rs | 8 ++--- .../src/sandbox/uninitialized_evolve.rs | 29 +++++++++---------- 8 files changed, 35 insertions(+), 44 deletions(-) diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index f2eb5727c..7a8fc70a7 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -63,8 +63,7 @@ fn guest_call_benchmark(c: &mut Criterion) { .register("HostAdd", |a: i32, b: i32| Ok(a + b)) .unwrap(); - let mut multiuse_sandbox: MultiUseSandbox = - uninitialized_sandbox.evolve().unwrap(); + let mut multiuse_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve().unwrap(); b.iter(|| { multiuse_sandbox diff --git a/src/hyperlight_host/examples/guest-debugging/main.rs b/src/hyperlight_host/examples/guest-debugging/main.rs index bb0511c86..6b1f46677 100644 --- a/src/hyperlight_host/examples/guest-debugging/main.rs +++ b/src/hyperlight_host/examples/guest-debugging/main.rs @@ -68,8 +68,7 @@ fn main() -> hyperlight_host::Result<()> { // Note: This function is unused, it's just here for demonstration purposes // Initialize sandboxes to be able to call host functions - let mut multi_use_sandbox_dbg: MultiUseSandbox = - uninitialized_sandbox_dbg.evolve()?; + let mut multi_use_sandbox_dbg: MultiUseSandbox = uninitialized_sandbox_dbg.evolve()?; let mut multi_use_sandbox: MultiUseSandbox = uninitialized_sandbox.evolve()?; // Call guest function diff --git a/src/hyperlight_host/examples/tracing-chrome/main.rs b/src/hyperlight_host/examples/tracing-chrome/main.rs index 0b52ebb9c..259a37057 100644 --- a/src/hyperlight_host/examples/tracing-chrome/main.rs +++ b/src/hyperlight_host/examples/tracing-chrome/main.rs @@ -32,9 +32,7 @@ fn main() -> Result<()> { // Create a new sandbox. let usandbox = UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)?; - let mut sbox = usandbox - .evolve() - .unwrap(); + let mut sbox = usandbox.evolve().unwrap(); // do the function call let current_time = std::time::Instant::now(); diff --git a/src/hyperlight_host/examples/tracing-tracy/main.rs b/src/hyperlight_host/examples/tracing-tracy/main.rs index bdf1accc9..03867f0d5 100644 --- a/src/hyperlight_host/examples/tracing-tracy/main.rs +++ b/src/hyperlight_host/examples/tracing-tracy/main.rs @@ -38,9 +38,7 @@ fn main() -> Result<()> { // Create a new sandbox. let usandbox = UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)?; - let mut sbox = usandbox - .evolve() - .unwrap(); + let mut sbox = usandbox.evolve().unwrap(); // do the function call let current_time = std::time::Instant::now(); diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 72157471f..3aeb04748 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -262,7 +262,11 @@ impl MultiUseSandbox { } impl Callable for MultiUseSandbox { - fn call(&mut self, func_name: &str, args: impl ParameterTuple) -> Result { + fn call( + &mut self, + func_name: &str, + args: impl ParameterTuple, + ) -> Result { self.call_guest_function_by_name(func_name, args) } } @@ -325,11 +329,12 @@ mod tests { .unwrap(); for i in 0..1000 { - sbox2.call::( - "PrintUsingPrintf", - format!("Hello World {}\n", i).to_string(), - ) - .unwrap(); + sbox2 + .call::( + "PrintUsingPrintf", + format!("Hello World {}\n", i).to_string(), + ) + .unwrap(); } } @@ -560,8 +565,7 @@ mod tests { ) .unwrap(); - let mut multi_use_sandbox: MultiUseSandbox = - usbox.evolve().unwrap(); + let mut multi_use_sandbox: MultiUseSandbox = usbox.evolve().unwrap(); let res: i32 = multi_use_sandbox .call_guest_function_by_name("GetStatic", ()) diff --git a/src/hyperlight_host/src/sandbox/mod.rs b/src/hyperlight_host/src/sandbox/mod.rs index 206fb30ad..07389c369 100644 --- a/src/hyperlight_host/src/sandbox/mod.rs +++ b/src/hyperlight_host/src/sandbox/mod.rs @@ -164,11 +164,9 @@ mod tests { )) .unwrap(); - let sandbox = uninitialized_sandbox - .evolve() - .unwrap_or_else(|_| { - panic!("Failed to initialize UninitializedSandbox thread {}", i) - }); + let sandbox = uninitialized_sandbox.evolve().unwrap_or_else(|_| { + panic!("Failed to initialize UninitializedSandbox thread {}", i) + }); sq.push(sandbox).unwrap_or_else(|_| { panic!("Failed to push UninitializedSandbox thread {}", i) diff --git a/src/hyperlight_host/src/sandbox/uninitialized.rs b/src/hyperlight_host/src/sandbox/uninitialized.rs index 8271b54d8..f5149f5cc 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized.rs @@ -806,11 +806,9 @@ mod tests { .host_print(format!("Print from UninitializedSandbox on Thread {}\n", i)) .unwrap(); - let sandbox = uninitialized_sandbox - .evolve() - .unwrap_or_else(|_| { - panic!("Failed to initialize UninitializedSandbox thread {}", i) - }); + let sandbox = uninitialized_sandbox.evolve().unwrap_or_else(|_| { + panic!("Failed to initialize UninitializedSandbox thread {}", i) + }); sq.push(sandbox).unwrap_or_else(|_| { panic!("Failed to push UninitializedSandbox thread {}", i) diff --git a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs index 55da42434..95732ad8f 100644 --- a/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs +++ b/src/hyperlight_host/src/sandbox/uninitialized_evolve.rs @@ -126,23 +126,20 @@ where #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")] pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result { - evolve_impl( - u_sbox, - |hf, hshm, vm, out_hdl, mem_hdl, dispatch_ptr| { + evolve_impl(u_sbox, |hf, hshm, vm, out_hdl, mem_hdl, dispatch_ptr| { + #[cfg(gdb)] + let dbg_mem_wrapper = dbg_mem_access_handler_wrapper(hshm.clone()); + Ok(MultiUseSandbox::from_uninit( + hf, + hshm, + vm, + out_hdl, + mem_hdl, + dispatch_ptr, #[cfg(gdb)] - let dbg_mem_wrapper = dbg_mem_access_handler_wrapper(hshm.clone()); - Ok(MultiUseSandbox::from_uninit( - hf, - hshm, - vm, - out_hdl, - mem_hdl, - dispatch_ptr, - #[cfg(gdb)] - dbg_mem_wrapper, - )) - }, - ) + dbg_mem_wrapper, + )) + }) } pub(crate) fn set_up_hypervisor_partition( From 6dae14d7ff5924fd3cb49eca947ad652aa13d99a Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Tue, 8 Jul 2025 17:22:46 +0100 Subject: [PATCH 16/18] fix license header Signed-off-by: Jorge Prendes --- src/hyperlight_host/src/sandbox/snapshot.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/hyperlight_host/src/sandbox/snapshot.rs b/src/hyperlight_host/src/sandbox/snapshot.rs index 76a6da0c5..d91f52437 100644 --- a/src/hyperlight_host/src/sandbox/snapshot.rs +++ b/src/hyperlight_host/src/sandbox/snapshot.rs @@ -1,3 +1,19 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + use crate::mem::shared_mem_snapshot::SharedMemorySnapshot; /// A snapshot capturing the state of the memory in a `MultiUseSandbox`. From b50c8a267f5c1a784f997af7f3b436fd6880405b Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Tue, 8 Jul 2025 17:59:12 +0100 Subject: [PATCH 17/18] fix benchmark to new API Signed-off-by: Jorge Prendes --- src/hyperlight_host/benches/benchmarks.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index 7a8fc70a7..1c7914109 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -43,13 +43,15 @@ fn guest_call_benchmark(c: &mut Criterion) { // Benchmarks a single guest function call. // The benchmark does include the time to reset the sandbox memory after the call. - group.bench_function("guest_call_with_reset", |b| { - let mut sandbox = create_multiuse_sandbox(); + group.bench_function("guest_call_with_restore", |b| { + let mut sbox = create_multiuse_sandbox(); + let snapshot = sbox.snapshot().unwrap(); b.iter(|| { - sandbox - .call_guest_function_by_name::("Echo", "hello\n".to_string()) - .unwrap() + sbox + .call::("Echo", "hello\n".to_string()) + .unwrap(); + sbox.restore(&snapshot).unwrap(); }); }); From cbf3729c62ace7be993366024b1d70ba2cd0ba50 Mon Sep 17 00:00:00 2001 From: Jorge Prendes Date: Wed, 9 Jul 2025 11:41:43 +0100 Subject: [PATCH 18/18] fix formatting again Signed-off-by: Jorge Prendes --- src/hyperlight_host/benches/benchmarks.rs | 4 +--- src/hyperlight_host/src/mem/mgr.rs | 1 - src/hyperlight_host/src/sandbox/initialized_multi_use.rs | 3 ++- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hyperlight_host/benches/benchmarks.rs b/src/hyperlight_host/benches/benchmarks.rs index 1c7914109..96cc7ecf0 100644 --- a/src/hyperlight_host/benches/benchmarks.rs +++ b/src/hyperlight_host/benches/benchmarks.rs @@ -48,9 +48,7 @@ fn guest_call_benchmark(c: &mut Criterion) { let snapshot = sbox.snapshot().unwrap(); b.iter(|| { - sbox - .call::("Echo", "hello\n".to_string()) - .unwrap(); + sbox.call::("Echo", "hello\n".to_string()).unwrap(); sbox.restore(&snapshot).unwrap(); }); }); diff --git a/src/hyperlight_host/src/mem/mgr.rs b/src/hyperlight_host/src/mem/mgr.rs index e5d327963..c7bab4ad3 100644 --- a/src/hyperlight_host/src/mem/mgr.rs +++ b/src/hyperlight_host/src/mem/mgr.rs @@ -263,7 +263,6 @@ where SharedMemorySnapshot::new(&mut self.shared_mem, self.mapped_rgns) } - /// This function restores a memory snapshot the given snapshot. /// /// Returns the number of memory regions mapped into the sandbox diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 3aeb04748..fd42f53d2 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -102,7 +102,8 @@ impl MultiUseSandbox { /// Restore the sandbox's memory to the state captured in the given snapshot. #[instrument(err(Debug), skip_all, parent = Span::current())] pub fn restore(&mut self, snapshot: &Snapshot) -> Result<()> { - let rgns_to_unmap = self.mem_mgr + let rgns_to_unmap = self + .mem_mgr .unwrap_mgr_mut() .restore_snapshot(&snapshot.inner)?; unsafe { self.vm.unmap_regions(rgns_to_unmap)? };