1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
use interpreter::Error;
use interpreter::module::check_limits;
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;
pub struct MemoryInstance {
buffer: RwLock<Vec<u8>>,
maximum_size: u32,
}
struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
buffer: &'a B,
offset: usize,
size: usize,
}
impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
fn range(&self) -> ::std::ops::Range<usize> {
self.offset..self.offset+self.size
}
fn slice(&self) -> &[u8] {
&self.buffer[self.range()]
}
}
impl MemoryInstance {
pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
check_limits(memory_type.limits())?;
if let Some(maximum_pages) = memory_type.limits().maximum() {
if maximum_pages > LINEAR_MEMORY_MAX_PAGES {
return Err(Error::Memory(format!("memory size must be at most 65536 pages")));
}
}
let memory = MemoryInstance {
buffer: RwLock::new(Vec::new()),
maximum_size: memory_type.limits().maximum()
.map(|s| s.saturating_mul(LINEAR_MEMORY_PAGE_SIZE))
.unwrap_or(u32::MAX),
};
if memory.grow(memory_type.limits().initial())? == u32::MAX {
return Err(Error::Memory(format!("error initializing {}-pages linear memory region", memory_type.limits().initial())));
}
Ok(Arc::new(memory))
}
pub fn size(&self) -> u32 {
self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
}
pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
let buffer = self.buffer.read();
let region = self.checked_region(&buffer, offset as usize, size)?;
Ok(region.slice().to_vec())
}
pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
let mut buffer = self.buffer.write();
let range = self.checked_region(&buffer, offset as usize, value.len())?.range();
buffer[range].copy_from_slice(value);
Ok(())
}
pub fn grow(&self, pages: u32) -> Result<u32, Error> {
let mut buffer = self.buffer.write();
let old_size = buffer.len() as u32;
match pages.checked_mul(LINEAR_MEMORY_PAGE_SIZE).and_then(|bytes| old_size.checked_add(bytes)) {
None => Ok(u32::MAX),
Some(new_size) if new_size > self.maximum_size => Ok(u32::MAX),
Some(new_size) => {
buffer.extend(vec![0; (new_size - old_size) as usize]);
Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
},
}
}
fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error>
where B: ::std::ops::Deref<Target=Vec<u8>>
{
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,
})
}
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(())
}
}