@@ -1188,14 +1188,15 @@ mod tests {
11881188
11891189 use hyperlight_common:: flatbuffer_wrappers:: guest_error:: ErrorCode ;
11901190 use hyperlight_testing:: sandbox_sizes:: { LARGE_HEAP_SIZE , MEDIUM_HEAP_SIZE , SMALL_HEAP_SIZE } ;
1191- use hyperlight_testing:: simple_guest_as_pathbuf;
1191+ use hyperlight_testing:: { c_simple_guest_as_pathbuf , simple_guest_as_pathbuf} ;
11921192
11931193 use crate :: func:: host_functions:: Registerable ;
11941194 #[ cfg( not( gdb) ) ]
11951195 use crate :: hypervisor:: hyperlight_vm:: test_support:: VmOperation ;
11961196 use crate :: mem:: memory_region:: { MemoryRegion , MemoryRegionFlags , MemoryRegionType } ;
11971197 use crate :: mem:: shared_mem:: { ExclusiveSharedMemory , GuestSharedMemory , SharedMemory as _} ;
11981198 use crate :: sandbox:: SandboxConfiguration ;
1199+ use crate :: sandbox:: uninitialized:: { GuestBlob , GuestEnvironment } ;
11991200 use crate :: {
12001201 GuestBinary , HyperlightError , MultiUseSandbox , Result , SandboxStatus , UninitializedSandbox ,
12011202 } ;
@@ -2260,6 +2261,189 @@ mod tests {
22602261 assert_eq ! ( target. mem_mgr. layout. heap_size( ) , 0x6000 ) ;
22612262 }
22622263
2264+ #[ test]
2265+ fn snapshot_restore_replaces_rust_guest_with_c_guest ( ) {
2266+ let init_data = b"cross-layout-init-data" ;
2267+ let source_env = GuestEnvironment {
2268+ guest_binary : GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2269+ init_data : Some ( GuestBlob {
2270+ data : init_data,
2271+ permissions : MemoryRegionFlags :: READ | MemoryRegionFlags :: WRITE ,
2272+ } ) ,
2273+ } ;
2274+ let mut source = UninitializedSandbox :: new ( source_env, None )
2275+ . unwrap ( )
2276+ . evolve ( )
2277+ . unwrap ( ) ;
2278+ let mut target =
2279+ UninitializedSandbox :: new ( GuestBinary :: FilePath ( simple_guest_as_pathbuf ( ) ) , None )
2280+ . unwrap ( )
2281+ . evolve ( )
2282+ . unwrap ( ) ;
2283+
2284+ assert_eq ! ( source. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2285+ assert_eq ! ( target. call:: <i32 >( "AddToStatic" , 17i32 ) . unwrap( ) , 17 ) ;
2286+ target. set_pt_root_finder ( Box :: new ( |_, _, root| vec ! [ root] ) ) ;
2287+ assert ! ( target. pt_root_finder. is_some( ) ) ;
2288+
2289+ assert_ne ! (
2290+ source. mem_mgr. layout. code_size( ) ,
2291+ target. mem_mgr. layout. code_size( )
2292+ ) ;
2293+ assert_ne ! (
2294+ source. mem_mgr. layout. init_data_size( ) ,
2295+ target. mem_mgr. layout. init_data_size( )
2296+ ) ;
2297+ assert_ne ! (
2298+ source. mem_mgr. layout. init_data_permissions( ) ,
2299+ target. mem_mgr. layout. init_data_permissions( )
2300+ ) ;
2301+
2302+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2303+ target. restore ( snapshot) . unwrap ( ) ;
2304+ assert ! ( target. pt_root_finder. is_none( ) ) ;
2305+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 512i32 ) . unwrap( ) , 512 ) ;
2306+ assert ! ( matches!(
2307+ target. call:: <i32 >( "GetStatic" , ( ) ) ,
2308+ Err ( HyperlightError :: GuestError (
2309+ ErrorCode :: GuestFunctionNotFound ,
2310+ name
2311+ ) ) if name == "GetStatic"
2312+ ) ) ;
2313+ }
2314+
2315+ #[ test]
2316+ fn snapshot_restore_replaces_c_guest_with_rust_guest ( ) {
2317+ let mut source =
2318+ UninitializedSandbox :: new ( GuestBinary :: FilePath ( simple_guest_as_pathbuf ( ) ) , None )
2319+ . unwrap ( )
2320+ . evolve ( )
2321+ . unwrap ( ) ;
2322+ assert_eq ! ( source. call:: <i32 >( "AddToStatic" , 42i32 ) . unwrap( ) , 42 ) ;
2323+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2324+
2325+ let mut target =
2326+ UninitializedSandbox :: new ( GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) , None )
2327+ . unwrap ( )
2328+ . evolve ( )
2329+ . unwrap ( ) ;
2330+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2331+
2332+ target. restore ( snapshot) . unwrap ( ) ;
2333+ assert_eq ! ( target. call:: <i32 >( "GetStatic" , ( ) ) . unwrap( ) , 42 ) ;
2334+ assert ! ( matches!(
2335+ target. call:: <i32 >( "StackAllocate" , 512i32 ) ,
2336+ Err ( HyperlightError :: GuestError (
2337+ ErrorCode :: GuestFunctionNotFound ,
2338+ name
2339+ ) ) if name == "StackAllocate"
2340+ ) ) ;
2341+ }
2342+
2343+ #[ test]
2344+ fn snapshot_restore_alternates_c_and_rust_guests ( ) {
2345+ let mut c_source =
2346+ UninitializedSandbox :: new ( GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) , None )
2347+ . unwrap ( )
2348+ . evolve ( )
2349+ . unwrap ( ) ;
2350+ assert_eq ! ( c_source. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2351+ let c_snapshot = c_source. snapshot ( ) . unwrap ( ) ;
2352+
2353+ let mut rust_source =
2354+ UninitializedSandbox :: new ( GuestBinary :: FilePath ( simple_guest_as_pathbuf ( ) ) , None )
2355+ . unwrap ( )
2356+ . evolve ( )
2357+ . unwrap ( ) ;
2358+ rust_source. call :: < i32 > ( "AddToStatic" , 42i32 ) . unwrap ( ) ;
2359+ let rust_snapshot = rust_source. snapshot ( ) . unwrap ( ) ;
2360+
2361+ let mut target =
2362+ UninitializedSandbox :: new ( GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) , None )
2363+ . unwrap ( )
2364+ . evolve ( )
2365+ . unwrap ( ) ;
2366+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2367+
2368+ target. restore ( rust_snapshot) . unwrap ( ) ;
2369+ assert_eq ! ( target. call:: <i32 >( "GetStatic" , ( ) ) . unwrap( ) , 42 ) ;
2370+ assert ! ( matches!(
2371+ target. call:: <i32 >( "StackAllocate" , 512i32 ) ,
2372+ Err ( HyperlightError :: GuestError (
2373+ ErrorCode :: GuestFunctionNotFound ,
2374+ name
2375+ ) ) if name == "StackAllocate"
2376+ ) ) ;
2377+
2378+ target. restore ( c_snapshot) . unwrap ( ) ;
2379+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 512i32 ) . unwrap( ) , 512 ) ;
2380+ assert ! ( matches!(
2381+ target. call:: <i32 >( "GetStatic" , ( ) ) ,
2382+ Err ( HyperlightError :: GuestError (
2383+ ErrorCode :: GuestFunctionNotFound ,
2384+ name
2385+ ) ) if name == "GetStatic"
2386+ ) ) ;
2387+ }
2388+
2389+ #[ test]
2390+ fn snapshot_restore_keeps_target_host_function_implementation ( ) {
2391+ let path = simple_guest_as_pathbuf ( ) ;
2392+ let mut source = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2393+ source
2394+ . register_host_function ( "Echo42" , || Ok ( 1i64 ) )
2395+ . unwrap ( ) ;
2396+ let mut source = source. evolve ( ) . unwrap ( ) ;
2397+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2398+
2399+ let path = simple_guest_as_pathbuf ( ) ;
2400+ let mut target = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2401+ target
2402+ . register_host_function ( "Echo42" , || Ok ( 42i64 ) )
2403+ . unwrap ( ) ;
2404+ let mut target = target. evolve ( ) . unwrap ( ) ;
2405+
2406+ target. restore ( snapshot) . unwrap ( ) ;
2407+ assert_eq ! (
2408+ target
2409+ . call:: <i64 >(
2410+ "CallGivenParamlessHostFuncThatReturnsI64" ,
2411+ "Echo42" . to_string( ) ,
2412+ )
2413+ . unwrap( ) ,
2414+ 42
2415+ ) ;
2416+ }
2417+
2418+ #[ test]
2419+ fn snapshot_restore_recovers_poison_with_different_guest ( ) {
2420+ let mut source =
2421+ UninitializedSandbox :: new ( GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) , None )
2422+ . unwrap ( )
2423+ . evolve ( )
2424+ . unwrap ( ) ;
2425+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2426+
2427+ let path = simple_guest_as_pathbuf ( ) ;
2428+ let mut target = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None )
2429+ . unwrap ( )
2430+ . evolve ( )
2431+ . unwrap ( ) ;
2432+ assert ! ( target. call:: <( ) >( "ExhaustHeap" , ( ) ) . is_err( ) ) ;
2433+ assert ! ( target. status( ) . is_poisoned( ) ) ;
2434+
2435+ target. restore ( snapshot) . unwrap ( ) ;
2436+ assert ! ( !target. status( ) . is_poisoned( ) ) ;
2437+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 512i32 ) . unwrap( ) , 512 ) ;
2438+ assert ! ( matches!(
2439+ target. call:: <i32 >( "GetStatic" , ( ) ) ,
2440+ Err ( HyperlightError :: GuestError (
2441+ ErrorCode :: GuestFunctionNotFound ,
2442+ name
2443+ ) ) if name == "GetStatic"
2444+ ) ) ;
2445+ }
2446+
22632447 /// Validation runs before any memory or vCPU mutation, so a
22642448 /// rejected `restore` leaves the target usable.
22652449 #[ test]
@@ -2271,14 +2455,14 @@ mod tests {
22712455 . unwrap ( ) ;
22722456 let mut source = source. evolve ( ) . unwrap ( ) ;
22732457
2458+ let map_mem = allocate_guest_memory ( ) ;
22742459 let path = simple_guest_as_pathbuf ( ) ;
22752460 let mut target = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None )
22762461 . unwrap ( )
22772462 . evolve ( )
22782463 . unwrap ( ) ;
22792464
22802465 target. call :: < i32 > ( "AddToStatic" , 5i32 ) . unwrap ( ) ;
2281- let map_mem = allocate_guest_memory ( ) ;
22822466 let guest_base = 0x200000000_usize ;
22832467 let region = region_for_memory ( & map_mem, guest_base, MemoryRegionFlags :: READ ) ;
22842468 // SAFETY: `map_mem` is page-aligned and outlives every use of `target`.
0 commit comments