@@ -289,6 +289,73 @@ impl TypedExecutionResult {
289289}
290290
291291impl Instance {
292+ /// Ensure the range is valid according to the currently available memory size.
293+ fn checked_memory_range (
294+ memory_data : * mut u8 ,
295+ memory_size : usize ,
296+ offset : u32 ,
297+ size : usize ,
298+ ) -> Result < core:: ops:: Range < usize > , ( ) > {
299+ // This is safe given usize::BITS >= u32::BITS, see https://doc.rust-lang.org/std/primitive.usize.html.
300+ let offset = offset as usize ;
301+ let has_memory = memory_data != std:: ptr:: null_mut ( ) ;
302+ if !has_memory || offset. checked_add ( size) . is_none ( ) || ( offset + size) > memory_size {
303+ return Err ( ( ) ) ;
304+ }
305+ Ok ( offset..offset + size)
306+ }
307+
308+ /// Obtain a read-only slice of underlying memory.
309+ ///
310+ /// # Safety
311+ /// These slices turn invalid if the memory is resized (i.e. via the WebAssembly `memory.grow` instruction)
312+ pub unsafe fn checked_memory_slice ( & self , offset : u32 , size : usize ) -> Result < & [ u8 ] , ( ) > {
313+ let memory_data = sys:: fizzy_get_instance_memory_data ( self . 0 . as_ptr ( ) ) ;
314+ let memory_size = sys:: fizzy_get_instance_memory_size ( self . 0 . as_ptr ( ) ) ;
315+ let range = Instance :: checked_memory_range ( memory_data, memory_size, offset, size) ?;
316+ // Slices allow empty length, but data must be a valid pointer.
317+ debug_assert ! ( memory_data != std:: ptr:: null_mut( ) ) ;
318+ let memory = std:: slice:: from_raw_parts ( memory_data, memory_size) ;
319+ Ok ( & memory[ range] )
320+ }
321+
322+ /// Obtain a mutable slice of underlying memory.
323+ ///
324+ /// # Safety
325+ /// These slices turn invalid if the memory is resized (i.e. via the WebAssembly `memory.grow` instruction)
326+ pub unsafe fn checked_memory_slice_mut (
327+ & mut self ,
328+ offset : u32 ,
329+ size : usize ,
330+ ) -> Result < & mut [ u8 ] , ( ) > {
331+ let memory_data = sys:: fizzy_get_instance_memory_data ( self . 0 . as_ptr ( ) ) ;
332+ let memory_size = sys:: fizzy_get_instance_memory_size ( self . 0 . as_ptr ( ) ) ;
333+ let range = Instance :: checked_memory_range ( memory_data, memory_size, offset, size) ?;
334+ // Slices allow empty length, but data must be a valid pointer.
335+ debug_assert ! ( memory_data != std:: ptr:: null_mut( ) ) ;
336+ let memory = std:: slice:: from_raw_parts_mut ( memory_data, memory_size) ;
337+ Ok ( & mut memory[ range] )
338+ }
339+
340+ /// Returns the current memory size, in bytes.
341+ pub fn memory_size ( & self ) -> usize {
342+ unsafe { sys:: fizzy_get_instance_memory_size ( self . 0 . as_ptr ( ) ) }
343+ }
344+
345+ /// Copies memory from `offset` to `target`, for the length of `target.len()`.
346+ pub fn memory_get ( & self , offset : u32 , target : & mut [ u8 ] ) -> Result < ( ) , ( ) > {
347+ let slice = unsafe { self . checked_memory_slice ( offset, target. len ( ) ) ? } ;
348+ target. copy_from_slice ( slice) ;
349+ Ok ( ( ) )
350+ }
351+
352+ /// Copies memory from `source` to `offset`, for the length of `source.len()`.
353+ pub fn memory_set ( & mut self , offset : u32 , source : & [ u8 ] ) -> Result < ( ) , ( ) > {
354+ let slice = unsafe { self . checked_memory_slice_mut ( offset, source. len ( ) ) ? } ;
355+ slice. copy_from_slice ( source) ;
356+ Ok ( ( ) )
357+ }
358+
292359 /// Get a read-only pointer to the module.
293360 unsafe fn get_module ( & self ) -> * const sys:: FizzyModule {
294361 sys:: fizzy_get_instance_module ( self . 0 . as_ptr ( ) )
@@ -755,4 +822,258 @@ mod tests {
755822 let result = instance. execute ( "bar" , & [ TypedValue :: F32 ( 1.0 ) , TypedValue :: F64 ( 2.0 ) ] , 0 ) ;
756823 assert ! ( result. is_err( ) ) ;
757824 }
825+
826+ #[ test]
827+ fn no_memory ( ) {
828+ /* wat2wasm
829+ (module)
830+ */
831+ let input = hex:: decode ( "0061736d01000000" ) . unwrap ( ) ;
832+
833+ let module = parse ( & input) ;
834+ assert ! ( module. is_ok( ) ) ;
835+ let instance = module. unwrap ( ) . instantiate ( ) ;
836+ assert ! ( instance. is_ok( ) ) ;
837+ let mut instance = instance. unwrap ( ) ;
838+
839+ assert_eq ! ( instance. memory_size( ) , 0 ) ;
840+
841+ // If there is no memory, do not allow any slice.
842+ unsafe {
843+ assert ! ( instance. checked_memory_slice( 0 , 0 ) . is_err( ) ) ;
844+ assert ! ( instance. checked_memory_slice_mut( 0 , 0 ) . is_err( ) ) ;
845+ assert ! ( instance. checked_memory_slice( 0 , 65536 ) . is_err( ) ) ;
846+ assert ! ( instance. checked_memory_slice_mut( 0 , 65536 ) . is_err( ) ) ;
847+ assert ! ( instance. checked_memory_slice( 65535 , 1 ) . is_err( ) ) ;
848+ assert ! ( instance. checked_memory_slice_mut( 65535 , 1 ) . is_err( ) ) ;
849+ assert ! ( instance. checked_memory_slice( 65535 , 2 ) . is_err( ) ) ;
850+ assert ! ( instance. checked_memory_slice_mut( 65535 , 2 ) . is_err( ) ) ;
851+ assert ! ( instance. checked_memory_slice( 65536 , 0 ) . is_err( ) ) ;
852+ assert ! ( instance. checked_memory_slice_mut( 65536 , 0 ) . is_err( ) ) ;
853+ assert ! ( instance. checked_memory_slice( 65536 , 1 ) . is_err( ) ) ;
854+ assert ! ( instance. checked_memory_slice_mut( 65536 , 1 ) . is_err( ) ) ;
855+ }
856+
857+ // Set memory via safe helper.
858+ assert ! ( instance. memory_set( 0 , & [ ] ) . is_err( ) ) ;
859+ assert ! ( instance. memory_set( 0 , & [ 0x11 , 0x22 ] ) . is_err( ) ) ;
860+ // Get memory via safe helper.
861+ let mut dst: Vec < u8 > = Vec :: new ( ) ;
862+ dst. resize ( 65536 , 0 ) ;
863+ // Reading empty slice.
864+ assert ! ( instance. memory_get( 0 , & mut dst[ 0 ..0 ] ) . is_err( ) ) ;
865+ // Reading 65536 bytes.
866+ assert ! ( instance. memory_get( 0 , & mut dst) . is_err( ) ) ;
867+ }
868+
869+ #[ test]
870+ fn empty_memory ( ) {
871+ /* wat2wasm
872+ (module
873+ ;; Memory is allowed, but no memory is allocated at start.
874+ (memory 0)
875+ )
876+ */
877+ let input = hex:: decode ( "0061736d010000000503010000" ) . unwrap ( ) ;
878+
879+ let module = parse ( & input) ;
880+ assert ! ( module. is_ok( ) ) ;
881+ let instance = module. unwrap ( ) . instantiate ( ) ;
882+ assert ! ( instance. is_ok( ) ) ;
883+ let mut instance = instance. unwrap ( ) ;
884+
885+ assert_eq ! ( instance. memory_size( ) , 0 ) ;
886+
887+ // If there is no memory, do not allow any slice.
888+ unsafe {
889+ assert ! ( instance. checked_memory_slice( 0 , 0 ) . is_ok( ) ) ;
890+ assert ! ( instance. checked_memory_slice_mut( 0 , 0 ) . is_ok( ) ) ;
891+ assert ! ( instance. checked_memory_slice( 0 , 65536 ) . is_err( ) ) ;
892+ assert ! ( instance. checked_memory_slice_mut( 0 , 65536 ) . is_err( ) ) ;
893+ assert ! ( instance. checked_memory_slice( 65535 , 1 ) . is_err( ) ) ;
894+ assert ! ( instance. checked_memory_slice_mut( 65535 , 1 ) . is_err( ) ) ;
895+ assert ! ( instance. checked_memory_slice( 65535 , 2 ) . is_err( ) ) ;
896+ assert ! ( instance. checked_memory_slice_mut( 65535 , 2 ) . is_err( ) ) ;
897+ assert ! ( instance. checked_memory_slice( 65536 , 0 ) . is_err( ) ) ;
898+ assert ! ( instance. checked_memory_slice_mut( 65536 , 0 ) . is_err( ) ) ;
899+ assert ! ( instance. checked_memory_slice( 65536 , 1 ) . is_err( ) ) ;
900+ assert ! ( instance. checked_memory_slice_mut( 65536 , 1 ) . is_err( ) ) ;
901+ }
902+
903+ // Set memory via safe helper.
904+ assert ! ( instance. memory_set( 0 , & [ ] ) . is_ok( ) ) ;
905+ assert ! ( instance. memory_set( 0 , & [ 0x11 , 0x22 ] ) . is_err( ) ) ;
906+ // Get memory via safe helper.
907+ let mut dst: Vec < u8 > = Vec :: new ( ) ;
908+ dst. resize ( 65536 , 0 ) ;
909+ // Reading empty slice.
910+ assert ! ( instance. memory_get( 0 , & mut dst[ 0 ..0 ] ) . is_ok( ) ) ;
911+ // Reading 65536 bytes.
912+ assert ! ( instance. memory_get( 0 , & mut dst) . is_err( ) ) ;
913+ }
914+
915+ #[ test]
916+ fn memory ( ) {
917+ /* wat2wasm
918+ (module
919+ (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0)))
920+ (func (export "peek") (param i32) (result i32) (i32.load (local.get 0)))
921+ (func (export "poke") (param i32) (param i32) (i32.store (local.get 0) (local.get 1)))
922+ (memory (export "mem") 1 2)
923+ )
924+ */
925+ let input = hex:: decode ( "0061736d01000000010b0260017f017f60027f7f00030403000001050401010102071c040467726f770000047065656b000104706f6b650002036d656d02000a1a030600200040000b070020002802000b0900200020013602000b" ) . unwrap ( ) ;
926+ let module = parse ( & input) ;
927+ assert ! ( module. is_ok( ) ) ;
928+ let instance = module. unwrap ( ) . instantiate ( ) ;
929+ assert ! ( instance. is_ok( ) ) ;
930+ let mut instance = instance. unwrap ( ) ;
931+
932+ assert_eq ! ( instance. memory_size( ) , 65536 ) ;
933+ unsafe {
934+ // Allow empty slices.
935+ assert ! ( instance. checked_memory_slice( 0 , 0 ) . is_ok( ) ) ;
936+ assert ! ( instance. checked_memory_slice_mut( 0 , 0 ) . is_ok( ) ) ;
937+ // Entire memory.
938+ assert ! ( instance. checked_memory_slice( 0 , 65536 ) . is_ok( ) ) ;
939+ assert ! ( instance. checked_memory_slice_mut( 0 , 65536 ) . is_ok( ) ) ;
940+ // Allow empty slices.
941+ assert ! ( instance. checked_memory_slice( 65535 , 0 ) . is_ok( ) ) ;
942+ assert ! ( instance. checked_memory_slice_mut( 65535 , 0 ) . is_ok( ) ) ;
943+ assert ! ( instance. checked_memory_slice( 65536 , 0 ) . is_ok( ) ) ;
944+ assert ! ( instance. checked_memory_slice_mut( 65536 , 0 ) . is_ok( ) ) ;
945+ // Single byte.
946+ assert ! ( instance. checked_memory_slice( 65535 , 1 ) . is_ok( ) ) ;
947+ assert ! ( instance. checked_memory_slice_mut( 65535 , 1 ) . is_ok( ) ) ;
948+ // Reading over.
949+ assert ! ( instance. checked_memory_slice( 65535 , 2 ) . is_err( ) ) ;
950+ assert ! ( instance. checked_memory_slice_mut( 65535 , 2 ) . is_err( ) ) ;
951+ assert ! ( instance. checked_memory_slice( 65536 , 1 ) . is_err( ) ) ;
952+ assert ! ( instance. checked_memory_slice_mut( 65536 , 1 ) . is_err( ) ) ;
953+ // Offset overflow.
954+ assert ! ( instance. checked_memory_slice( 65537 , 0 ) . is_err( ) ) ;
955+ assert ! ( instance. checked_memory_slice_mut( 65537 , 0 ) . is_err( ) ) ;
956+ }
957+
958+ // Grow with a single page.
959+ let result = instance
960+ . execute ( "grow" , & [ TypedValue :: U32 ( 1 ) ] , 0 )
961+ . expect ( "successful execution" ) ;
962+ assert ! ( !result. trapped( ) ) ;
963+ assert_eq ! (
964+ result
965+ . value( )
966+ . expect( "expected value" )
967+ . as_u32( )
968+ . expect( "expected u32 result" ) ,
969+ 1
970+ ) ;
971+ // Expect new total memory size.
972+ assert_eq ! ( instance. memory_size( ) , 65536 * 2 ) ;
973+
974+ // Set memory via slices.
975+ unsafe {
976+ let mem = instance
977+ . checked_memory_slice_mut ( 0 , 65536 )
978+ . expect ( "valid mutable slice" ) ;
979+ assert_eq ! ( mem[ 0 ] , 0 ) ;
980+ assert_eq ! ( mem[ 1 ] , 0 ) ;
981+ assert_eq ! ( mem[ 2 ] , 0 ) ;
982+ assert_eq ! ( mem[ 3 ] , 0 ) ;
983+ mem[ 0 ] = 42 ;
984+ }
985+ unsafe {
986+ // Check that const slice matches up.
987+ let mem = instance. checked_memory_slice ( 0 , 5 ) . expect ( "valid slice" ) ;
988+ assert_eq ! ( mem[ 0 ] , 42 ) ;
989+ assert_eq ! ( mem[ 1 ] , 0 ) ;
990+ assert_eq ! ( mem[ 2 ] , 0 ) ;
991+ assert_eq ! ( mem[ 3 ] , 0 ) ;
992+ }
993+ let result = instance
994+ . execute ( "peek" , & [ TypedValue :: U32 ( 0 ) ] , 0 )
995+ . expect ( "successful execution" ) ;
996+ assert ! ( !result. trapped( ) ) ;
997+ assert_eq ! (
998+ result
999+ . value( )
1000+ . expect( "expected value" )
1001+ . as_u32( )
1002+ . expect( "expected u32 result" ) ,
1003+ 42
1004+ ) ;
1005+
1006+ // Remember, by now we have grown memory to two pages.
1007+
1008+ // Set memory via safe helper.
1009+ assert ! ( instance. memory_set( 0 , & [ ] ) . is_ok( ) ) ;
1010+ assert ! ( instance. memory_set( 65536 + 65535 , & [ ] ) . is_ok( ) ) ;
1011+ assert ! ( instance. memory_set( 65536 + 65536 , & [ ] ) . is_ok( ) ) ;
1012+ assert ! ( instance. memory_set( 65536 + 65537 , & [ ] ) . is_err( ) ) ;
1013+ assert ! ( instance. memory_set( 0 , & [ 0x11 , 0x22 , 0x33 , 0x44 ] ) . is_ok( ) ) ;
1014+ assert ! ( instance
1015+ . memory_set( 65536 + 65532 , & [ 0x11 , 0x22 , 0x33 , 0x44 ] )
1016+ . is_ok( ) ) ;
1017+ assert ! ( instance
1018+ . memory_set( 65536 + 65533 , & [ 0x11 , 0x22 , 0x33 , 0x44 ] )
1019+ . is_err( ) ) ;
1020+ assert ! ( instance
1021+ . memory_set( 65536 + 65534 , & [ 0x11 , 0x22 , 0x33 , 0x44 ] )
1022+ . is_err( ) ) ;
1023+ assert ! ( instance
1024+ . memory_set( 65536 + 65535 , & [ 0x11 , 0x22 , 0x33 , 0x44 ] )
1025+ . is_err( ) ) ;
1026+ assert ! ( instance
1027+ . memory_set( 65536 + 65536 , & [ 0x11 , 0x22 , 0x33 , 0x44 ] )
1028+ . is_err( ) ) ;
1029+ assert ! ( instance
1030+ . memory_set( 65536 + 65537 , & [ 0x11 , 0x22 , 0x33 , 0x44 ] )
1031+ . is_err( ) ) ;
1032+
1033+ let result = instance
1034+ . execute ( "peek" , & [ TypedValue :: U32 ( 0 ) ] , 0 )
1035+ . expect ( "successful execution" ) ;
1036+ assert ! ( !result. trapped( ) ) ;
1037+ assert_eq ! (
1038+ result
1039+ . value( )
1040+ . expect( "expected value" )
1041+ . as_u32( )
1042+ . expect( "expected u32 result" ) ,
1043+ 0x44332211
1044+ ) ;
1045+
1046+ // Change memory via wasm.
1047+ let result = instance
1048+ . execute (
1049+ "poke" ,
1050+ & [ TypedValue :: U32 ( 0 ) , TypedValue :: U32 ( 0x88776655 ) ] ,
1051+ 0 ,
1052+ )
1053+ . expect ( "successful execution" ) ;
1054+ assert ! ( !result. trapped( ) ) ;
1055+
1056+ // Read memory via safe helper.
1057+ let mut dst: Vec < u8 > = Vec :: new ( ) ;
1058+ dst. resize ( 65536 , 0 ) ;
1059+ // Reading 65536 bytes.
1060+ assert ! ( instance. memory_get( 0 , & mut dst) . is_ok( ) ) ;
1061+ // Only checking the first 4.
1062+ assert_eq ! ( dst[ 0 ..4 ] , [ 0x55 , 0x66 , 0x77 , 0x88 ] ) ;
1063+
1064+ // Read into empty slice.
1065+ assert ! ( instance. memory_get( 0 , & mut dst[ 0 ..0 ] ) . is_ok( ) ) ;
1066+ assert ! ( instance. memory_get( 65536 + 65535 , & mut dst[ 0 ..0 ] ) . is_ok( ) ) ;
1067+ assert ! ( instance. memory_get( 65536 + 65536 , & mut dst[ 0 ..0 ] ) . is_ok( ) ) ;
1068+ assert ! ( instance. memory_get( 65536 + 65537 , & mut dst[ 0 ..0 ] ) . is_err( ) ) ;
1069+
1070+ // Read into short slice.
1071+ assert ! ( instance. memory_get( 0 , & mut dst[ 0 ..4 ] ) . is_ok( ) ) ;
1072+ assert ! ( instance. memory_get( 65536 + 65532 , & mut dst[ 0 ..4 ] ) . is_ok( ) ) ;
1073+ assert ! ( instance. memory_get( 65536 + 65533 , & mut dst[ 0 ..4 ] ) . is_err( ) ) ;
1074+ assert ! ( instance. memory_get( 65536 + 65534 , & mut dst[ 0 ..4 ] ) . is_err( ) ) ;
1075+ assert ! ( instance. memory_get( 65536 + 65535 , & mut dst[ 0 ..4 ] ) . is_err( ) ) ;
1076+ assert ! ( instance. memory_get( 65536 + 65536 , & mut dst[ 0 ..4 ] ) . is_err( ) ) ;
1077+ assert ! ( instance. memory_get( 65536 + 65537 , & mut dst[ 0 ..4 ] ) . is_err( ) ) ;
1078+ }
7581079}
0 commit comments