1 // Copyright (c) 2013-2017 Sandstorm Development Group, Inc. and contributors 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 use std::cell::{Cell, RefCell}; 22 use std::slice; 23 use std::u64; 24 25 use crate::private::units::*; 26 use crate::message; 27 use crate::message::{Allocator, ReaderSegments}; 28 use crate::{Error, OutputSegments, Result, Word}; 29 30 pub type SegmentId = u32; 31 32 pub struct ReadLimiter { 33 pub limit: Cell<u64>, 34 } 35 36 impl ReadLimiter { new(limit: u64) -> ReadLimiter37 pub fn new(limit: u64) -> ReadLimiter { 38 ReadLimiter { limit: Cell::new(limit) } 39 } 40 41 #[inline] can_read(&self, amount: u64) -> Result<()>42 pub fn can_read(&self, amount: u64) -> Result<()> { 43 let current = self.limit.get(); 44 if amount > current { 45 Err(Error::failed(format!("read limit exceeded"))) 46 } else { 47 self.limit.set(current - amount); 48 Ok(()) 49 } 50 } 51 } 52 53 pub trait ReaderArena { get_segment(&self, id: u32) -> Result<(*const Word, u32)>54 fn get_segment(&self, id: u32) -> Result<(*const Word, u32)>; check_offset(&self, segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word>55 fn check_offset(&self, segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word>; contains_interval(&self, segment_id: u32, start: *const Word, size: usize) -> Result<()>56 fn contains_interval(&self, segment_id: u32, start: *const Word, size: usize) -> Result<()>; amplified_read(&self, virtual_amount: u64) -> Result<()>57 fn amplified_read(&self, virtual_amount: u64) -> Result<()>; 58 59 // TODO(version 0.9): Consider putting extract_cap(), inject_cap(), drop_cap() here 60 // and on message::Reader. Then we could get rid of Imbue and ImbueMut, and 61 // layout::StructReader, layout::ListReader, etc. could drop their `cap_table` fields. 62 } 63 64 pub struct ReaderArenaImpl<S> { 65 segments: S, 66 read_limiter: ReadLimiter, 67 } 68 69 impl <S> ReaderArenaImpl <S> where S: ReaderSegments { new(segments: S, options: message::ReaderOptions) -> Self70 pub fn new(segments: S, 71 options: message::ReaderOptions) 72 -> Self 73 { 74 let limiter = ReadLimiter::new(options.traversal_limit_in_words); 75 ReaderArenaImpl { 76 segments: segments, 77 read_limiter: limiter, 78 } 79 } 80 into_segments(self) -> S81 pub fn into_segments(self) -> S { 82 self.segments 83 } 84 } 85 86 impl <S> ReaderArena for ReaderArenaImpl<S> where S: ReaderSegments { get_segment<'a>(&'a self, id: u32) -> Result<(*const Word, u32)>87 fn get_segment<'a>(&'a self, id: u32) -> Result<(*const Word, u32)> { 88 match self.segments.get_segment(id) { 89 Some(seg) => Ok((seg.as_ptr(), seg.len() as u32)), 90 None => Err(Error::failed(format!("Invalid segment id: {}", id))), 91 } 92 } 93 check_offset(&self, segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word>94 fn check_offset(&self, segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word> { 95 let (segment_start, segment_len) = self.get_segment(segment_id)?; 96 let this_start: usize = segment_start as usize; 97 let this_size: usize = segment_len as usize * BYTES_PER_WORD; 98 let offset: i64 = offset_in_words as i64 * BYTES_PER_WORD as i64; 99 let start_idx = start as usize; 100 if start_idx < this_start || ((start_idx - this_start) as i64 + offset) as usize > this_size { 101 Err(Error::failed(format!("message contained out-of-bounds pointer"))) 102 } else { 103 unsafe { Ok(start.offset(offset_in_words as isize)) } 104 } 105 } 106 contains_interval(&self, id: u32, start: *const Word, size_in_words: usize) -> Result<()>107 fn contains_interval(&self, id: u32, start: *const Word, size_in_words: usize) -> Result<()> { 108 let (segment_start, segment_len) = self.get_segment(id)?; 109 let this_start: usize = segment_start as usize; 110 let this_size: usize = segment_len as usize * BYTES_PER_WORD; 111 let start = start as usize; 112 let size = size_in_words * BYTES_PER_WORD; 113 114 if !(start >= this_start && start - this_start + size <= this_size) { 115 Err(Error::failed(format!("message contained out-of-bounds pointer"))) 116 } else { 117 self.read_limiter.can_read(size_in_words as u64) 118 } 119 } 120 amplified_read(&self, virtual_amount: u64) -> Result<()>121 fn amplified_read(&self, virtual_amount: u64) -> Result<()> { 122 self.read_limiter.can_read(virtual_amount) 123 } 124 } 125 126 pub trait BuilderArena: ReaderArena { 127 // These methods all take an immutable &self because otherwise a StructBuilder<'a> 128 // would need a `&'a mut BuilderArena` and `StructBuilder::borrow()` would 129 // have lifetime issues. (If `'a: 'b`, then a `&'a (BuilderArena + 'a)` can be 130 // converted to a `&'b (BuilderArena + 'b)`, but a `&'a mut (BuilderArena + 'a)` 131 // *cannot* be converted to a `&'b mut (BuilderArena + 'b)`. See some discussion here: 132 // https://botbot.me/mozilla/rust/2017-01-31/?msg=80228117&page=19 .) allocate(&self, segment_id: u32, amount: WordCount32) -> Option<u32>133 fn allocate(&self, segment_id: u32, amount: WordCount32) -> Option<u32>; allocate_anywhere(&self, amount: u32) -> (SegmentId, u32)134 fn allocate_anywhere(&self, amount: u32) -> (SegmentId, u32); get_segment_mut(&self, id: u32) -> (*mut Word, u32)135 fn get_segment_mut(&self, id: u32) -> (*mut Word, u32); 136 as_reader<'a>(&'a self) -> &'a dyn ReaderArena137 fn as_reader<'a>(&'a self) -> &'a dyn ReaderArena; 138 } 139 140 pub struct BuilderArenaImplInner<A> where A: Allocator { 141 allocator: A, 142 143 // TODO(perf): Try using smallvec to avoid heap allocations in the single-segment case? 144 segments: Vec<(*mut Word, u32)>, 145 allocated: Vec<u32>, // number of words allocated for each segment. 146 } 147 148 pub struct BuilderArenaImpl<A> where A: Allocator { 149 inner: RefCell<BuilderArenaImplInner<A>> 150 } 151 152 impl <A> BuilderArenaImpl<A> where A: Allocator { new(allocator: A) -> Self153 pub fn new(allocator: A) -> Self { 154 BuilderArenaImpl { 155 inner: RefCell::new(BuilderArenaImplInner { 156 allocator: allocator, 157 segments: Vec::new(), 158 allocated: Vec::new(), 159 }), 160 } 161 } 162 allocate_segment(&self, minimum_size: u32) -> Result<()>163 pub fn allocate_segment(&self, minimum_size: u32) -> Result<()> { 164 self.inner.borrow_mut().allocate_segment(minimum_size) 165 } 166 get_segments_for_output<'a>(&'a self) -> OutputSegments<'a>167 pub fn get_segments_for_output<'a>(&'a self) -> OutputSegments<'a> { 168 let reff = self.inner.borrow(); 169 if reff.allocated.len() == 1 { 170 let seg = reff.segments[0]; 171 172 // The user must mutably borrow the `message::Builder` to be able to modify segment memory. 173 // No such borrow will be possible while `self` is still immutably borrowed from this method, 174 // so returning this slice is safe. 175 let slice = unsafe { slice::from_raw_parts(seg.0 as *const _, reff.allocated[0] as usize) }; 176 OutputSegments::SingleSegment([slice]) 177 } else { 178 let mut v = Vec::with_capacity(reff.allocated.len()); 179 for idx in 0..reff.allocated.len() { 180 let seg = reff.segments[idx]; 181 182 // See safety argument in above branch. 183 let slice = unsafe { slice::from_raw_parts(seg.0 as *const _, reff.allocated[idx] as usize) }; 184 v.push(slice); 185 } 186 OutputSegments::MultiSegment(v) 187 } 188 } 189 len(&self) -> usize190 pub fn len(&self) -> usize { 191 self.inner.borrow().allocated.len() 192 } 193 } 194 195 impl <A> ReaderArena for BuilderArenaImpl<A> where A: Allocator { get_segment(&self, id: u32) -> Result<(*const Word, u32)>196 fn get_segment(&self, id: u32) -> Result<(*const Word, u32)> { 197 let borrow = self.inner.borrow(); 198 let seg = borrow.segments[id as usize]; 199 Ok((seg.0 as *const _, seg.1)) 200 } 201 check_offset(&self, _segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word>202 fn check_offset(&self, _segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word> { 203 unsafe { Ok(start.offset(offset_in_words as isize)) } 204 } 205 contains_interval(&self, _id: u32, _start: *const Word, _size: usize) -> Result<()>206 fn contains_interval(&self, _id: u32, _start: *const Word, _size: usize) -> Result<()> { 207 Ok(()) 208 } 209 amplified_read(&self, _virtual_amount: u64) -> Result<()>210 fn amplified_read(&self, _virtual_amount: u64) -> Result<()> { 211 Ok(()) 212 } 213 } 214 215 impl <A> BuilderArenaImplInner<A> where A: Allocator { allocate_segment(&mut self, minimum_size: WordCount32) -> Result<()>216 fn allocate_segment(&mut self, minimum_size: WordCount32) -> Result<()> { 217 let seg = self.allocator.allocate_segment(minimum_size); 218 self.segments.push(seg); 219 self.allocated.push(0); 220 Ok(()) 221 } 222 allocate(&mut self, segment_id: u32, amount: WordCount32) -> Option<u32>223 fn allocate(&mut self, segment_id: u32, amount: WordCount32) -> Option<u32> { 224 if amount > self.get_segment_mut(segment_id).1 as u32 - self.allocated[segment_id as usize] { 225 None 226 } else { 227 let result = self.allocated[segment_id as usize]; 228 self.allocated[segment_id as usize] += amount; 229 Some(result) 230 } 231 } 232 allocate_anywhere(&mut self, amount: u32) -> (SegmentId, u32)233 fn allocate_anywhere(&mut self, amount: u32) -> (SegmentId, u32) { 234 // first try the existing segments, then try allocating a new segment. 235 let allocated_len = self.allocated.len() as u32; 236 for segment_id in 0.. allocated_len { 237 match self.allocate(segment_id, amount) { 238 Some(idx) => return (segment_id, idx), 239 None => (), 240 } 241 } 242 243 // Need to allocate a new segment. 244 245 self.allocate_segment(amount).expect("allocate new segment"); 246 (allocated_len, 247 self.allocate(allocated_len, amount).expect("use freshly-allocated segment")) 248 } 249 get_segment_mut(&mut self, id: u32) -> (*mut Word, u32)250 fn get_segment_mut(&mut self, id: u32) -> (*mut Word, u32) { 251 self.segments[id as usize] 252 } 253 254 } 255 256 impl <A> BuilderArena for BuilderArenaImpl<A> where A: Allocator { allocate(&self, segment_id: u32, amount: WordCount32) -> Option<u32>257 fn allocate(&self, segment_id: u32, amount: WordCount32) -> Option<u32> { 258 self.inner.borrow_mut().allocate(segment_id, amount) 259 } 260 allocate_anywhere(&self, amount: u32) -> (SegmentId, u32)261 fn allocate_anywhere(&self, amount: u32) -> (SegmentId, u32) { 262 self.inner.borrow_mut().allocate_anywhere(amount) 263 } 264 get_segment_mut(&self, id: u32) -> (*mut Word, u32)265 fn get_segment_mut(&self, id: u32) -> (*mut Word, u32) { 266 self.inner.borrow_mut().get_segment_mut(id) 267 } 268 as_reader<'a>(&'a self) -> &'a dyn ReaderArena269 fn as_reader<'a>(&'a self) -> &'a dyn ReaderArena { 270 self 271 } 272 } 273 274 impl <A> Drop for BuilderArenaImplInner<A> where A: Allocator { drop(&mut self)275 fn drop(&mut self) { 276 if self.allocated.len() > 0 { 277 self.allocator.pre_drop(self.allocated[0]); 278 } 279 } 280 } 281 282 pub struct NullArena; 283 284 impl ReaderArena for NullArena { get_segment(&self, _id: u32) -> Result<(*const Word, u32)>285 fn get_segment(&self, _id: u32) -> Result<(*const Word, u32)> { 286 Err(Error::failed(format!("tried to read from null arena"))) 287 } 288 check_offset(&self, _segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word>289 fn check_offset(&self, _segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word> { 290 unsafe { Ok(start.offset(offset_in_words as isize)) } 291 } 292 contains_interval(&self, _id: u32, _start: *const Word, _size: usize) -> Result<()>293 fn contains_interval(&self, _id: u32, _start: *const Word, _size: usize) -> Result<()> { 294 Ok(()) 295 } 296 amplified_read(&self, _virtual_amount: u64) -> Result<()>297 fn amplified_read(&self, _virtual_amount: u64) -> Result<()> { 298 Ok(()) 299 } 300 } 301 302 impl BuilderArena for NullArena { allocate(&self, _segment_id: u32, _amount: WordCount32) -> Option<u32>303 fn allocate(&self, _segment_id: u32, _amount: WordCount32) -> Option<u32> { 304 None 305 } 306 allocate_anywhere(&self, _amount: u32) -> (SegmentId, u32)307 fn allocate_anywhere(&self, _amount: u32) -> (SegmentId, u32) { 308 panic!("tried to allocate from a null arena") 309 } 310 get_segment_mut(&self, _id: u32) -> (*mut Word, u32)311 fn get_segment_mut(&self, _id: u32) -> (*mut Word, u32) { 312 (::std::ptr::null_mut(), 0) 313 } 314 as_reader<'a>(&'a self) -> &'a dyn ReaderArena315 fn as_reader<'a>(&'a self) -> &'a dyn ReaderArena { 316 self 317 } 318 } 319 320