diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index 7aadcae..1c208a7 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -18,6 +18,22 @@ pub struct MemoryInstance { maximum_size: u32, } +struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref> { + buffer: &'a B, + offset: usize, + size: usize, +} + +impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref> { + fn range(&self) -> ::std::ops::Range { + self.offset..self.offset+self.size + } + + fn slice(&self) -> &[u8] { + &self.buffer[self.range()] + } +} + impl MemoryInstance { /// Create new linear memory instance. pub fn new(memory_type: &MemoryType) -> Result, Error> { @@ -48,36 +64,18 @@ impl MemoryInstance { /// Get data at given offset. pub fn get(&self, offset: u32, size: usize) -> Result, Error> { - let begin = offset as usize; - let end = match begin.checked_add(size) { - Some(end) => end, - None => return Err(Error::Memory(format!("trying to read memory block of size {} from offset {}", size, offset))), - }; - let buffer = self.buffer.read(); - if buffer.len() < end { - return Err(Error::Memory(format!("trying to read region [{}..{}] in memory [0..{}]", begin, end, buffer.len()))); - } + let region = self.checked_region(&buffer, offset as usize, size)?; - Ok(buffer[begin..end].to_vec()) + Ok(region.slice().to_vec()) } /// Set data at given offset. pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> { - let size = value.len(); - let begin = offset as usize; - let end = match begin.checked_add(size) { - Some(end) => end, - None => return Err(Error::Memory(format!("trying to update memory block of size {} from offset {}", size, offset))), - }; - let mut buffer = self.buffer.write(); - if buffer.len() < end { - return Err(Error::Memory(format!("trying to update region [{}..{}] in memory [0..{}]", begin, end, buffer.len()))); - } + let range = self.checked_region(&buffer, offset as usize, value.len())?.range(); - let mut mut_buffer = buffer.as_mut_slice(); - mut_buffer[begin..end].copy_from_slice(value); + buffer[range].copy_from_slice(value); Ok(()) } @@ -96,4 +94,37 @@ impl MemoryInstance { }, } } + + fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result, Error> + where B: ::std::ops::Deref> + { + let end = offset.checked_add(size) + .ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?; + + if end > buffer.len() { + return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len()))); + } + + Ok(CheckedRegion { + buffer: buffer, + offset: offset, + size: size, + }) + } + + /// Copy memory region + pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> { + let buffer = self.buffer.write(); + + let read_region = self.checked_region(&buffer, src_offset, len)?; + let write_region = self.checked_region(&buffer, dst_offset, len)?; + + unsafe { ::std::ptr::copy( + buffer[read_region.range()].as_ptr(), + buffer[write_region.range()].as_ptr() as *mut _, + len, + )} + + Ok(()) + } }