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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::{MemoryType, ResizableLimits};
use interpreter::{Error, UserError};
use interpreter::module::check_limits;
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;
pub struct MemoryInstance<E: UserError> {
limits: ResizableLimits,
buffer: RwLock<Vec<u8>>,
maximum_size: u32,
_dummy: ::std::marker::PhantomData<E>,
}
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<E> MemoryInstance<E> where E: UserError {
pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error<E>> {
check_limits(memory_type.limits())?;
let maximum_size = match memory_type.limits().maximum() {
Some(maximum_pages) if maximum_pages > LINEAR_MEMORY_MAX_PAGES =>
return Err(Error::Memory(format!("maximum memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES))),
Some(maximum_pages) => maximum_pages.saturating_mul(LINEAR_MEMORY_PAGE_SIZE),
None => u32::MAX,
};
let initial_size = calculate_memory_size(0, memory_type.limits().initial(), maximum_size)
.ok_or(Error::Memory(format!("initial memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES)))?;
let memory = MemoryInstance {
limits: memory_type.limits().clone(),
buffer: RwLock::new(vec![0; initial_size as usize]),
maximum_size: maximum_size,
_dummy: Default::default(),
};
Ok(Arc::new(memory))
}
pub fn limits(&self) -> &ResizableLimits {
&self.limits
}
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<E>> {
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<E>> {
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<E>> {
let mut buffer = self.buffer.write();
let old_size = buffer.len() as u32;
match calculate_memory_size(old_size, pages, self.maximum_size) {
None => Ok(u32::MAX),
Some(new_size) => {
buffer.resize(new_size as usize, 0);
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<E>>
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<E>> {
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(())
}
pub fn zero(&self, offset: usize, len: usize) -> Result<(), Error<E>> {
let mut buffer = self.buffer.write();
let range = self.checked_region(&buffer, offset, len)?.range();
for val in &mut buffer[range] { *val = 0 }
Ok(())
}
}
fn calculate_memory_size(old_size: u32, additional_pages: u32, maximum_size: u32) -> Option<u32> {
additional_pages
.checked_mul(LINEAR_MEMORY_PAGE_SIZE)
.and_then(|size| size.checked_add(old_size))
.and_then(|size| if size > maximum_size {
None
} else {
Some(size)
})
}