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