@@ -498,7 +498,7 @@ impl MemBlock
498498
499499 /// Grow to a new size in bytes
500500 /// This operation is a no-op if the existing size
501- /// is greater or equal to the requested size
501+ /// is less than or equal to the requested size
502502 ///
503503 /// Note: this operation must be guarded by the VM
504504 pub fn grow ( & mut self , mut new_size : usize ) -> usize
@@ -512,7 +512,6 @@ impl MemBlock
512512
513513 let cur_size = * self . cur_size ;
514514
515- // Growing the memory block, need to map as read | write
516515 if new_size <= cur_size {
517516 return cur_size;
518517 }
@@ -523,6 +522,7 @@ impl MemBlock
523522 let map_size = new_size - cur_size;
524523 assert ! ( map_size % self . page_size == 0 ) ;
525524
525+ // Growing the memory block, need to map as read | write
526526 let mem_block = unsafe { libc:: mmap (
527527 map_addr,
528528 map_size,
@@ -542,7 +542,7 @@ impl MemBlock
542542 new_size
543543 }
544544
545- // Create a new thread-local view on this memory block
545+ // Create a new thread-local view of this memory block
546546 fn new_view ( & self ) -> MemView
547547 {
548548 MemView {
@@ -626,6 +626,38 @@ impl MemView
626626 }
627627 }
628628
629+ /// Read a value at an address
630+ /// The address does not need to be aligned
631+ pub fn read < T > ( & self , addr : usize ) -> T where T : Copy
632+ {
633+ // Check that the address is within bounds
634+ let cur_size = unsafe { * self . cur_size } ;
635+ if addr + size_of :: < T > ( ) > cur_size {
636+ panic ! ( "attempting to read past end of heap" ) ;
637+ }
638+
639+ unsafe {
640+ let ptr = self . mem_block . add ( addr) as * const T ;
641+ std:: ptr:: read_unaligned ( ptr)
642+ }
643+ }
644+
645+ /// Write a value at an address
646+ /// The address does not need to be aligned
647+ pub fn write < T > ( & mut self , addr : usize , val : T ) where T : Copy
648+ {
649+ // Check that the address is within bounds
650+ let cur_size = unsafe { * self . cur_size } ;
651+ if addr + size_of :: < T > ( ) > cur_size {
652+ panic ! ( "attempting to write past end of heap" ) ;
653+ }
654+
655+ unsafe {
656+ let ptr = self . mem_block . add ( addr) as * mut T ;
657+ std:: ptr:: write_unaligned ( ptr, val) ;
658+ }
659+ }
660+
629661 /// Read a value at the current PC and then increment the PC
630662 pub fn read_pc < T > ( & self , pc : & mut usize ) -> T where T : Copy
631663 {
@@ -1404,60 +1436,53 @@ impl Thread
14041436 self . push ( v. as_f32 ( ) as i32 ) ;
14051437 }
14061438
1439+ // Note: load/store accept unaligned addresses
14071440 Op :: load_u8 => {
14081441 let addr = self . pop ( ) . as_usize ( ) ;
1409- let heap_ptr = self . get_heap_ptr_mut ( addr, 1 ) ;
1410- let val: u8 = unsafe { * heap_ptr } ;
1442+ let val: u8 = self . heap . read ( addr) ;
14111443 self . push ( val) ;
14121444 }
14131445
14141446 Op :: load_u16 => {
14151447 let addr = self . pop ( ) . as_usize ( ) ;
1416- let heap_ptr = self . get_heap_ptr_mut ( addr, 1 ) ;
1417- let val: u16 = unsafe { * heap_ptr } ;
1448+ let val: u16 = self . heap . read ( addr) ;
14181449 self . push ( val) ;
14191450 }
14201451
14211452 Op :: load_u32 => {
14221453 let addr = self . pop ( ) . as_usize ( ) ;
1423- let heap_ptr = self . get_heap_ptr_mut ( addr, 1 ) ;
1424- let val: u32 = unsafe { * heap_ptr } ;
1454+ let val: u32 = self . heap . read ( addr) ;
14251455 self . push ( val) ;
14261456 }
14271457
14281458 Op :: load_u64 => {
14291459 let addr = self . pop ( ) . as_usize ( ) ;
1430- let heap_ptr = self . get_heap_ptr_mut ( addr, 1 ) ;
1431- let val: u64 = unsafe { * heap_ptr } ;
1460+ let val: u64 = self . heap . read ( addr) ;
14321461 self . push ( val) ;
14331462 }
14341463
14351464 Op :: store_u8 => {
14361465 let val = self . pop ( ) . as_u8 ( ) ;
14371466 let addr = self . pop ( ) . as_usize ( ) ;
1438- let heap_ptr = self . get_heap_ptr_mut ( addr, 1 ) ;
1439- unsafe { * heap_ptr = val; }
1467+ self . heap . write ( addr, val) ;
14401468 }
14411469
14421470 Op :: store_u16 => {
14431471 let val = self . pop ( ) . as_u16 ( ) ;
14441472 let addr = self . pop ( ) . as_usize ( ) ;
1445- let heap_ptr = self . get_heap_ptr_mut ( addr, 1 ) ;
1446- unsafe { * heap_ptr = val; }
1473+ self . heap . write ( addr, val) ;
14471474 }
14481475
14491476 Op :: store_u32 => {
14501477 let val = self . pop ( ) . as_u32 ( ) ;
14511478 let addr = self . pop ( ) . as_usize ( ) ;
1452- let heap_ptr = self . get_heap_ptr_mut ( addr, 1 ) ;
1453- unsafe { * heap_ptr = val; }
1479+ self . heap . write ( addr, val) ;
14541480 }
14551481
14561482 Op :: store_u64 => {
14571483 let val = self . pop ( ) . as_u64 ( ) ;
14581484 let addr = self . pop ( ) . as_usize ( ) ;
1459- let heap_ptr = self . get_heap_ptr_mut ( addr, 1 ) ;
1460- unsafe { * heap_ptr = val; }
1485+ self . heap . write ( addr, val) ;
14611486 }
14621487
14631488 Op :: atomic_load_u64 => {
@@ -1923,6 +1948,22 @@ mod tests
19231948 eval_i64 ( ".data; .zero 255; .code; push_i8 0; push_i8 77; store_u8; push_i8 11; ret;" , 11 ) ;
19241949 }
19251950
1951+ #[ test]
1952+ fn test_unaligned_load_store ( )
1953+ {
1954+ // Store and load a u64 at an unaligned address
1955+ eval_i64 ( ".data; .zero 255; .code; push 1; push 0x1122334455667788; store_u64; push 1; load_u64; ret;" , 0x1122334455667788 ) ;
1956+
1957+ // Store and load a u32 at an unaligned address
1958+ eval_i64 ( ".data; .zero 255; .code; push 3; push 0x0AABBCCD; store_u32; push 3; load_u32; ret;" , 0x0AABBCCD ) ;
1959+
1960+ // Store and load a u16 at an unaligned address
1961+ eval_i64 ( ".data; .zero 255; .code; push 7; push 0x1234; store_u16; push 7; load_u16; ret;" , 0x1234 ) ;
1962+
1963+ // Unaligned stores should not clobber neighbouring bytes
1964+ eval_i64 ( ".data; .zero 255; .code; push 0; push 0xFF; store_u8; push 1; push 0x1122334455667788; store_u64; push 0; load_u8; ret;" , 0xFF ) ;
1965+ }
1966+
19261967 #[ test]
19271968 fn test_setn ( )
19281969 {
0 commit comments