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