@@ -1194,14 +1194,15 @@ mod tests {
11941194
11951195 use hyperlight_common:: flatbuffer_wrappers:: guest_error:: ErrorCode ;
11961196 use hyperlight_testing:: sandbox_sizes:: { LARGE_HEAP_SIZE , MEDIUM_HEAP_SIZE , SMALL_HEAP_SIZE } ;
1197- use hyperlight_testing:: simple_guest_as_pathbuf;
1197+ use hyperlight_testing:: { c_simple_guest_as_pathbuf , simple_guest_as_pathbuf} ;
11981198
11991199 use crate :: func:: host_functions:: Registerable ;
12001200 #[ cfg( not( gdb) ) ]
12011201 use crate :: hypervisor:: hyperlight_vm:: test_support:: VmOperation ;
12021202 use crate :: mem:: memory_region:: { MemoryRegion , MemoryRegionFlags , MemoryRegionType } ;
12031203 use crate :: mem:: shared_mem:: { ExclusiveSharedMemory , GuestSharedMemory , SharedMemory as _} ;
12041204 use crate :: sandbox:: SandboxConfiguration ;
1205+ use crate :: sandbox:: uninitialized:: { GuestBlob , GuestEnvironment } ;
12051206 use crate :: {
12061207 GuestBinary , HyperlightError , MultiUseSandbox , Result , SandboxStatus , UninitializedSandbox ,
12071208 } ;
@@ -2256,6 +2257,203 @@ mod tests {
22562257 assert_eq ! ( target. mem_mgr. layout. heap_size( ) , 0x6000 ) ;
22572258 }
22582259
2260+ #[ test]
2261+ fn snapshot_restore_replaces_rust_guest_with_c_guest ( ) {
2262+ let init_data = b"cross-layout-init-data" ;
2263+ let source_env = GuestEnvironment {
2264+ guest_binary : GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2265+ init_data : Some ( GuestBlob {
2266+ data : init_data,
2267+ permissions : MemoryRegionFlags :: READ | MemoryRegionFlags :: WRITE ,
2268+ } ) ,
2269+ } ;
2270+ let mut source = UninitializedSandbox :: new ( source_env, None )
2271+ . unwrap ( )
2272+ . evolve ( )
2273+ . unwrap ( ) ;
2274+ let mut target = UninitializedSandbox :: new (
2275+ GuestBinary :: FilePath ( simple_guest_as_pathbuf ( ) ) ,
2276+ None ,
2277+ )
2278+ . unwrap ( )
2279+ . evolve ( )
2280+ . unwrap ( ) ;
2281+
2282+ assert_eq ! ( source. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2283+ assert_eq ! ( target. call:: <i32 >( "AddToStatic" , 17i32 ) . unwrap( ) , 17 ) ;
2284+ target. set_pt_root_finder ( Box :: new ( |_, _, root| vec ! [ root] ) ) ;
2285+ assert ! ( target. pt_root_finder. is_some( ) ) ;
2286+
2287+ assert_ne ! (
2288+ source. mem_mgr. layout. code_size( ) ,
2289+ target. mem_mgr. layout. code_size( )
2290+ ) ;
2291+ assert_ne ! (
2292+ source. mem_mgr. layout. init_data_size( ) ,
2293+ target. mem_mgr. layout. init_data_size( )
2294+ ) ;
2295+ assert_ne ! (
2296+ source. mem_mgr. layout. init_data_permissions( ) ,
2297+ target. mem_mgr. layout. init_data_permissions( )
2298+ ) ;
2299+
2300+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2301+ target. restore ( snapshot) . unwrap ( ) ;
2302+ assert ! ( target. pt_root_finder. is_none( ) ) ;
2303+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 512i32 ) . unwrap( ) , 512 ) ;
2304+ assert ! ( matches!(
2305+ target. call:: <i32 >( "GetStatic" , ( ) ) ,
2306+ Err ( HyperlightError :: GuestError (
2307+ ErrorCode :: GuestFunctionNotFound ,
2308+ name
2309+ ) ) if name == "GetStatic"
2310+ ) ) ;
2311+ }
2312+
2313+ #[ test]
2314+ fn snapshot_restore_replaces_c_guest_with_rust_guest ( ) {
2315+ let mut source = UninitializedSandbox :: new (
2316+ GuestBinary :: FilePath ( simple_guest_as_pathbuf ( ) ) ,
2317+ None ,
2318+ )
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 = UninitializedSandbox :: new (
2326+ GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2327+ None ,
2328+ )
2329+ . unwrap ( )
2330+ . evolve ( )
2331+ . unwrap ( ) ;
2332+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2333+
2334+ target. restore ( snapshot) . unwrap ( ) ;
2335+ assert_eq ! ( target. call:: <i32 >( "GetStatic" , ( ) ) . unwrap( ) , 42 ) ;
2336+ assert ! ( matches!(
2337+ target. call:: <i32 >( "StackAllocate" , 512i32 ) ,
2338+ Err ( HyperlightError :: GuestError (
2339+ ErrorCode :: GuestFunctionNotFound ,
2340+ name
2341+ ) ) if name == "StackAllocate"
2342+ ) ) ;
2343+ }
2344+
2345+ #[ test]
2346+ fn snapshot_restore_alternates_c_and_rust_guests ( ) {
2347+ let mut c_source = UninitializedSandbox :: new (
2348+ GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2349+ None ,
2350+ )
2351+ . unwrap ( )
2352+ . evolve ( )
2353+ . unwrap ( ) ;
2354+ assert_eq ! ( c_source. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2355+ let c_snapshot = c_source. snapshot ( ) . unwrap ( ) ;
2356+
2357+ let mut rust_source = UninitializedSandbox :: new (
2358+ GuestBinary :: FilePath ( simple_guest_as_pathbuf ( ) ) ,
2359+ None ,
2360+ )
2361+ . unwrap ( )
2362+ . evolve ( )
2363+ . unwrap ( ) ;
2364+ rust_source. call :: < i32 > ( "AddToStatic" , 42i32 ) . unwrap ( ) ;
2365+ let rust_snapshot = rust_source. snapshot ( ) . unwrap ( ) ;
2366+
2367+ let mut target = UninitializedSandbox :: new (
2368+ GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2369+ None ,
2370+ )
2371+ . unwrap ( )
2372+ . evolve ( )
2373+ . unwrap ( ) ;
2374+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2375+
2376+ target. restore ( rust_snapshot) . unwrap ( ) ;
2377+ assert_eq ! ( target. call:: <i32 >( "GetStatic" , ( ) ) . unwrap( ) , 42 ) ;
2378+ assert ! ( matches!(
2379+ target. call:: <i32 >( "StackAllocate" , 512i32 ) ,
2380+ Err ( HyperlightError :: GuestError (
2381+ ErrorCode :: GuestFunctionNotFound ,
2382+ name
2383+ ) ) if name == "StackAllocate"
2384+ ) ) ;
2385+
2386+ target. restore ( c_snapshot) . unwrap ( ) ;
2387+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 512i32 ) . unwrap( ) , 512 ) ;
2388+ assert ! ( matches!(
2389+ target. call:: <i32 >( "GetStatic" , ( ) ) ,
2390+ Err ( HyperlightError :: GuestError (
2391+ ErrorCode :: GuestFunctionNotFound ,
2392+ name
2393+ ) ) if name == "GetStatic"
2394+ ) ) ;
2395+ }
2396+
2397+ #[ test]
2398+ fn snapshot_restore_keeps_target_host_function_implementation ( ) {
2399+ let path = simple_guest_as_pathbuf ( ) ;
2400+ let mut source = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2401+ source
2402+ . register_host_function ( "Echo42" , || Ok ( 1i64 ) )
2403+ . unwrap ( ) ;
2404+ let mut source = source. evolve ( ) . unwrap ( ) ;
2405+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2406+
2407+ let path = simple_guest_as_pathbuf ( ) ;
2408+ let mut target = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2409+ target
2410+ . register_host_function ( "Echo42" , || Ok ( 42i64 ) )
2411+ . unwrap ( ) ;
2412+ let mut target = target. evolve ( ) . unwrap ( ) ;
2413+
2414+ target. restore ( snapshot) . unwrap ( ) ;
2415+ assert_eq ! (
2416+ target
2417+ . call:: <i64 >(
2418+ "CallGivenParamlessHostFuncThatReturnsI64" ,
2419+ "Echo42" . to_string( ) ,
2420+ )
2421+ . unwrap( ) ,
2422+ 42
2423+ ) ;
2424+ }
2425+
2426+ #[ test]
2427+ fn snapshot_restore_recovers_poison_with_different_guest ( ) {
2428+ let mut source = UninitializedSandbox :: new (
2429+ GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2430+ None ,
2431+ )
2432+ . unwrap ( )
2433+ . evolve ( )
2434+ . unwrap ( ) ;
2435+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2436+
2437+ let path = simple_guest_as_pathbuf ( ) ;
2438+ let mut target = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None )
2439+ . unwrap ( )
2440+ . evolve ( )
2441+ . unwrap ( ) ;
2442+ assert ! ( target. call:: <( ) >( "ExhaustHeap" , ( ) ) . is_err( ) ) ;
2443+ assert ! ( target. status( ) . is_poisoned( ) ) ;
2444+
2445+ target. restore ( snapshot) . unwrap ( ) ;
2446+ assert ! ( !target. status( ) . is_poisoned( ) ) ;
2447+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 512i32 ) . unwrap( ) , 512 ) ;
2448+ assert ! ( matches!(
2449+ target. call:: <i32 >( "GetStatic" , ( ) ) ,
2450+ Err ( HyperlightError :: GuestError (
2451+ ErrorCode :: GuestFunctionNotFound ,
2452+ name
2453+ ) ) if name == "GetStatic"
2454+ ) ) ;
2455+ }
2456+
22592457 /// Validation runs before any memory or vCPU mutation, so a
22602458 /// rejected `restore` leaves the target usable.
22612459 #[ test]
0 commit comments