@@ -1254,14 +1254,15 @@ mod tests {
12541254
12551255 use hyperlight_common:: flatbuffer_wrappers:: guest_error:: ErrorCode ;
12561256 use hyperlight_testing:: sandbox_sizes:: { LARGE_HEAP_SIZE , MEDIUM_HEAP_SIZE , SMALL_HEAP_SIZE } ;
1257- use hyperlight_testing:: simple_guest_as_pathbuf;
1257+ use hyperlight_testing:: { c_simple_guest_as_pathbuf , simple_guest_as_pathbuf} ;
12581258
12591259 #[ cfg( not( gdb) ) ]
12601260 use crate :: hypervisor:: hyperlight_vm:: { HyperlightVmError , test_support:: VmOperation } ;
12611261 use crate :: func:: host_functions:: Registerable ;
12621262 use crate :: mem:: memory_region:: { MemoryRegion , MemoryRegionFlags , MemoryRegionType } ;
12631263 use crate :: mem:: shared_mem:: { ExclusiveSharedMemory , GuestSharedMemory , SharedMemory as _} ;
12641264 use crate :: sandbox:: SandboxConfiguration ;
1265+ use crate :: sandbox:: uninitialized:: { GuestBlob , GuestEnvironment } ;
12651266 use crate :: {
12661267 GuestBinary , HyperlightError , MultiUseSandbox , Result , SandboxStatus , UninitializedSandbox ,
12671268 } ;
@@ -2485,7 +2486,7 @@ mod tests {
24852486 target. restore ( snapshot) . unwrap ( ) ;
24862487 assert_eq ! ( target. mem_mgr. layout. heap_size( ) , 0x6000 ) ;
24872488 assert ! ( target. call:: <i32 >( "CallMalloc" , 0x10_000i32 ) . is_err( ) ) ;
2488- assert ! ( target. poisoned ( ) ) ;
2489+ assert ! ( target. status ( ) . is_poisoned ( ) ) ;
24892490 }
24902491
24912492 #[ test]
@@ -2515,7 +2516,7 @@ mod tests {
25152516 assert_eq ! ( target. mem_mgr. layout. input_data_size( ) , 0x2000 ) ;
25162517 assert_eq ! ( target. mem_mgr. layout. output_data_size( ) , 0x2000 ) ;
25172518 assert ! ( target. call:: <String >( "Echo" , large) . is_err( ) ) ;
2518- assert ! ( !target. poisoned ( ) ) ;
2519+ assert ! ( !target. status ( ) . is_poisoned ( ) ) ;
25192520 assert_eq ! (
25202521 target. call:: <String >( "Echo" , "small" . to_string( ) ) . unwrap( ) ,
25212522 "small"
@@ -2575,6 +2576,203 @@ mod tests {
25752576 assert_eq ! ( target. mem_mgr. layout. heap_size( ) , 0x6000 ) ;
25762577 }
25772578
2579+ #[ test]
2580+ fn snapshot_restore_replaces_rust_guest_with_c_guest ( ) {
2581+ let init_data = b"cross-layout-init-data" ;
2582+ let source_env = GuestEnvironment {
2583+ guest_binary : GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2584+ init_data : Some ( GuestBlob {
2585+ data : init_data,
2586+ permissions : MemoryRegionFlags :: READ | MemoryRegionFlags :: WRITE ,
2587+ } ) ,
2588+ } ;
2589+ let mut source = UninitializedSandbox :: new ( source_env, None )
2590+ . unwrap ( )
2591+ . evolve ( )
2592+ . unwrap ( ) ;
2593+ let mut target = UninitializedSandbox :: new (
2594+ GuestBinary :: FilePath ( simple_guest_as_pathbuf ( ) ) ,
2595+ None ,
2596+ )
2597+ . unwrap ( )
2598+ . evolve ( )
2599+ . unwrap ( ) ;
2600+
2601+ assert_eq ! ( source. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2602+ assert_eq ! ( target. call:: <i32 >( "AddToStatic" , 17i32 ) . unwrap( ) , 17 ) ;
2603+ target. set_pt_root_finder ( Box :: new ( |_, _, root| vec ! [ root] ) ) ;
2604+ assert ! ( target. pt_root_finder. is_some( ) ) ;
2605+
2606+ assert_ne ! (
2607+ source. mem_mgr. layout. code_size( ) ,
2608+ target. mem_mgr. layout. code_size( )
2609+ ) ;
2610+ assert_ne ! (
2611+ source. mem_mgr. layout. init_data_size( ) ,
2612+ target. mem_mgr. layout. init_data_size( )
2613+ ) ;
2614+ assert_ne ! (
2615+ source. mem_mgr. layout. init_data_permissions( ) ,
2616+ target. mem_mgr. layout. init_data_permissions( )
2617+ ) ;
2618+
2619+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2620+ target. restore ( snapshot) . unwrap ( ) ;
2621+ assert ! ( target. pt_root_finder. is_none( ) ) ;
2622+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 512i32 ) . unwrap( ) , 512 ) ;
2623+ assert ! ( matches!(
2624+ target. call:: <i32 >( "GetStatic" , ( ) ) ,
2625+ Err ( HyperlightError :: GuestError (
2626+ ErrorCode :: GuestFunctionNotFound ,
2627+ name
2628+ ) ) if name == "GetStatic"
2629+ ) ) ;
2630+ }
2631+
2632+ #[ test]
2633+ fn snapshot_restore_replaces_c_guest_with_rust_guest ( ) {
2634+ let mut source = UninitializedSandbox :: new (
2635+ GuestBinary :: FilePath ( simple_guest_as_pathbuf ( ) ) ,
2636+ None ,
2637+ )
2638+ . unwrap ( )
2639+ . evolve ( )
2640+ . unwrap ( ) ;
2641+ assert_eq ! ( source. call:: <i32 >( "AddToStatic" , 42i32 ) . unwrap( ) , 42 ) ;
2642+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2643+
2644+ let mut target = UninitializedSandbox :: new (
2645+ GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2646+ None ,
2647+ )
2648+ . unwrap ( )
2649+ . evolve ( )
2650+ . unwrap ( ) ;
2651+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2652+
2653+ target. restore ( snapshot) . unwrap ( ) ;
2654+ assert_eq ! ( target. call:: <i32 >( "GetStatic" , ( ) ) . unwrap( ) , 42 ) ;
2655+ assert ! ( matches!(
2656+ target. call:: <i32 >( "StackAllocate" , 512i32 ) ,
2657+ Err ( HyperlightError :: GuestError (
2658+ ErrorCode :: GuestFunctionNotFound ,
2659+ name
2660+ ) ) if name == "StackAllocate"
2661+ ) ) ;
2662+ }
2663+
2664+ #[ test]
2665+ fn snapshot_restore_alternates_c_and_rust_guests ( ) {
2666+ let mut c_source = UninitializedSandbox :: new (
2667+ GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2668+ None ,
2669+ )
2670+ . unwrap ( )
2671+ . evolve ( )
2672+ . unwrap ( ) ;
2673+ assert_eq ! ( c_source. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2674+ let c_snapshot = c_source. snapshot ( ) . unwrap ( ) ;
2675+
2676+ let mut rust_source = UninitializedSandbox :: new (
2677+ GuestBinary :: FilePath ( simple_guest_as_pathbuf ( ) ) ,
2678+ None ,
2679+ )
2680+ . unwrap ( )
2681+ . evolve ( )
2682+ . unwrap ( ) ;
2683+ rust_source. call :: < i32 > ( "AddToStatic" , 42i32 ) . unwrap ( ) ;
2684+ let rust_snapshot = rust_source. snapshot ( ) . unwrap ( ) ;
2685+
2686+ let mut target = UninitializedSandbox :: new (
2687+ GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2688+ None ,
2689+ )
2690+ . unwrap ( )
2691+ . evolve ( )
2692+ . unwrap ( ) ;
2693+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 256i32 ) . unwrap( ) , 256 ) ;
2694+
2695+ target. restore ( rust_snapshot) . unwrap ( ) ;
2696+ assert_eq ! ( target. call:: <i32 >( "GetStatic" , ( ) ) . unwrap( ) , 42 ) ;
2697+ assert ! ( matches!(
2698+ target. call:: <i32 >( "StackAllocate" , 512i32 ) ,
2699+ Err ( HyperlightError :: GuestError (
2700+ ErrorCode :: GuestFunctionNotFound ,
2701+ name
2702+ ) ) if name == "StackAllocate"
2703+ ) ) ;
2704+
2705+ target. restore ( c_snapshot) . unwrap ( ) ;
2706+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 512i32 ) . unwrap( ) , 512 ) ;
2707+ assert ! ( matches!(
2708+ target. call:: <i32 >( "GetStatic" , ( ) ) ,
2709+ Err ( HyperlightError :: GuestError (
2710+ ErrorCode :: GuestFunctionNotFound ,
2711+ name
2712+ ) ) if name == "GetStatic"
2713+ ) ) ;
2714+ }
2715+
2716+ #[ test]
2717+ fn snapshot_restore_keeps_target_host_function_implementation ( ) {
2718+ let path = simple_guest_as_pathbuf ( ) ;
2719+ let mut source = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2720+ source
2721+ . register_host_function ( "Echo42" , || Ok ( 1i64 ) )
2722+ . unwrap ( ) ;
2723+ let mut source = source. evolve ( ) . unwrap ( ) ;
2724+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2725+
2726+ let path = simple_guest_as_pathbuf ( ) ;
2727+ let mut target = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None ) . unwrap ( ) ;
2728+ target
2729+ . register_host_function ( "Echo42" , || Ok ( 42i64 ) )
2730+ . unwrap ( ) ;
2731+ let mut target = target. evolve ( ) . unwrap ( ) ;
2732+
2733+ target. restore ( snapshot) . unwrap ( ) ;
2734+ assert_eq ! (
2735+ target
2736+ . call:: <i64 >(
2737+ "CallGivenParamlessHostFuncThatReturnsI64" ,
2738+ "Echo42" . to_string( ) ,
2739+ )
2740+ . unwrap( ) ,
2741+ 42
2742+ ) ;
2743+ }
2744+
2745+ #[ test]
2746+ fn snapshot_restore_recovers_poison_with_different_guest ( ) {
2747+ let mut source = UninitializedSandbox :: new (
2748+ GuestBinary :: FilePath ( c_simple_guest_as_pathbuf ( ) ) ,
2749+ None ,
2750+ )
2751+ . unwrap ( )
2752+ . evolve ( )
2753+ . unwrap ( ) ;
2754+ let snapshot = source. snapshot ( ) . unwrap ( ) ;
2755+
2756+ let path = simple_guest_as_pathbuf ( ) ;
2757+ let mut target = UninitializedSandbox :: new ( GuestBinary :: FilePath ( path) , None )
2758+ . unwrap ( )
2759+ . evolve ( )
2760+ . unwrap ( ) ;
2761+ assert ! ( target. call:: <( ) >( "ExhaustHeap" , ( ) ) . is_err( ) ) ;
2762+ assert ! ( target. status( ) . is_poisoned( ) ) ;
2763+
2764+ target. restore ( snapshot) . unwrap ( ) ;
2765+ assert ! ( !target. status( ) . is_poisoned( ) ) ;
2766+ assert_eq ! ( target. call:: <i32 >( "StackAllocate" , 512i32 ) . unwrap( ) , 512 ) ;
2767+ assert ! ( matches!(
2768+ target. call:: <i32 >( "GetStatic" , ( ) ) ,
2769+ Err ( HyperlightError :: GuestError (
2770+ ErrorCode :: GuestFunctionNotFound ,
2771+ name
2772+ ) ) if name == "GetStatic"
2773+ ) ) ;
2774+ }
2775+
25782776 /// Validation runs before any memory or vCPU mutation, so a
25792777 /// rejected `restore` leaves the target usable.
25802778 #[ test]
0 commit comments