diff --git a/src/lib.rs b/src/lib.rs index d2ead2493c04..591cf5766234 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -301,6 +301,7 @@ type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tc impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; + type MemoryExtra = (); type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; @@ -405,8 +406,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } fn find_foreign_static( - tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, + tcx: TyCtxtAt<'a, 'tcx, 'tcx>, + memory_extra: &Self::MemoryExtra, ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { @@ -417,8 +419,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { let alloc = match &link_name[..] { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized - let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; - Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi) + let size = tcx.data_layout.pointer_size; + let data = vec![0; size.bytes() as usize]; + let extra = AllocationExtra::memory_allocated(size, memory_extra); + Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi, extra) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), @@ -434,9 +438,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn adjust_static_allocation( - alloc: &'_ Allocation - ) -> Cow<'_, Allocation> { + fn adjust_static_allocation<'b>( + alloc: &'b Allocation, + memory_extra: &Self::MemoryExtra, + ) -> Cow<'b, Allocation> { + let extra = AllocationExtra::memory_allocated( + Size::from_bytes(alloc.bytes.len() as u64), + memory_extra, + ); let alloc: Allocation = Allocation { bytes: alloc.bytes.clone(), relocations: Relocations::from_presorted( @@ -447,7 +456,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { undef_mask: alloc.undef_mask.clone(), align: alloc.align, mutability: alloc.mutability, - extra: Self::AllocExtra::default(), + extra, }; Cow::Owned(alloc) } diff --git a/src/range_map.rs b/src/range_map.rs index 74a49bf83b81..762b17b1ae33 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -16,13 +16,6 @@ pub struct RangeMap { map: BTreeMap, } -impl Default for RangeMap { - #[inline(always)] - fn default() -> Self { - RangeMap::new() - } -} - // The derived `Ord` impl sorts first by the first field, then, if the fields are the same, // by the second field. // This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all @@ -73,9 +66,15 @@ impl Range { } impl RangeMap { + /// Create a new RangeMap for the given size, and with the given initial value used for + /// the entire range. #[inline(always)] - pub fn new() -> RangeMap { - RangeMap { map: BTreeMap::new() } + pub fn new(size: Size, init: T) -> RangeMap { + let mut map = RangeMap { map: BTreeMap::new() }; + if size.bytes() > 0 { + map.map.insert(Range { start: 0, end: size.bytes() }, init); + } + map } fn iter_with_range<'a>( @@ -95,6 +94,9 @@ impl RangeMap { ) } + /// Provide read-only iteration over everything in the given range. This does + /// *not* split items if they overlap with the edges. Do not use this to mutate + /// through interior mutability. pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data) } @@ -140,8 +142,7 @@ impl RangeMap { /// Provide mutable iteration over everything in the given range. As a side-effect, /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. - /// If there are gaps, leave them be. - pub fn iter_mut_with_gaps<'a>( + pub fn iter_mut<'a>( &'a mut self, offset: Size, len: Size, @@ -174,64 +175,6 @@ impl RangeMap { }, ) } - - /// Provide a mutable iterator over everything in the given range, with the same side-effects as - /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default - /// before yielding them in the iterator. - /// This is also how you insert. - pub fn iter_mut<'a>(&'a mut self, offset: Size, len: Size) -> impl Iterator + 'a - where - T: Clone + Default, - { - if len.bytes() > 0 { - let offset = offset.bytes(); - let len = len.bytes(); - - // Do a first iteration to collect the gaps - let mut gaps = Vec::new(); - let mut last_end = offset; - for (range, _) in self.iter_with_range(offset, len) { - if last_end < range.start { - gaps.push(Range { - start: last_end, - end: range.start, - }); - } - last_end = range.end; - } - if last_end < offset + len { - gaps.push(Range { - start: last_end, - end: offset + len, - }); - } - - // Add default for all gaps - for gap in gaps { - let old = self.map.insert(gap, Default::default()); - assert!(old.is_none()); - } - } - - // Now provide mutable iteration - self.iter_mut_with_gaps(offset, len) - } - - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - let mut remove = Vec::new(); - for (range, data) in &self.map { - if !f(data) { - remove.push(*range); - } - } - - for range in remove { - self.map.remove(&range); - } - } } #[cfg(test)] @@ -239,14 +182,13 @@ mod tests { use super::*; /// Query the map at every offset in the range and collect the results. - fn to_vec(map: &RangeMap, offset: u64, len: u64, default: Option) -> Vec { + fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .into_iter() .map(|i| map .iter(Size::from_bytes(i), Size::from_bytes(1)) .next() .map(|&t| t) - .or(default) .unwrap() ) .collect() @@ -254,13 +196,13 @@ mod tests { #[test] fn basic_insert() { - let mut map = RangeMap::::new(); + let mut map = RangeMap::::new(Size::from_bytes(20), -1); // Insert for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; } // Check - assert_eq!(to_vec(&map, 10, 1, None), vec![42]); + assert_eq!(to_vec(&map, 10, 1), vec![42]); // Insert with size 0 for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { @@ -269,12 +211,12 @@ mod tests { for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) { *x = 19; } - assert_eq!(to_vec(&map, 10, 2, Some(-1)), vec![42, -1]); + assert_eq!(to_vec(&map, 10, 2), vec![42, -1]); } #[test] fn gaps() { - let mut map = RangeMap::::new(); + let mut map = RangeMap::::new(Size::from_bytes(20), -1); for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { *x = 42; } @@ -282,11 +224,10 @@ mod tests { *x = 43; } assert_eq!( - to_vec(&map, 10, 10, Some(-1)), + to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] ); - // Now request a range that needs three gaps filled for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { if *x < 42 { *x = 23; @@ -294,9 +235,18 @@ mod tests { } assert_eq!( - to_vec(&map, 10, 10, None), + to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23] ); - assert_eq!(to_vec(&map, 13, 5, None), vec![23, 23, 43, 23, 23]); + assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); + + // Now request a range that goes beyond the initial size + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) { + *x = 19; + } + assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1)) + .map(|&t| t).collect::>(), vec![19]); + assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1)) + .map(|&t| t).collect::>(), vec![]); } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f292d083637a..22ec6ffe6f50 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -126,7 +126,7 @@ impl State { } /// Extra per-allocation state -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, @@ -289,9 +289,8 @@ impl<'tcx> Stacks { ) -> EvalResult<'tcx> { trace!("deref for tag {:?} as {:?}: {:?}, size {}", ptr.tag, kind, ptr, size.bytes()); - let mut stacks = self.stacks.borrow_mut(); - // We need `iter_mut` because `iter` would skip gaps! - for stack in stacks.iter_mut(ptr.offset, size) { + let stacks = self.stacks.borrow(); + for stack in stacks.iter(ptr.offset, size) { stack.deref(ptr.tag, kind).map_err(EvalErrorKind::MachineError)?; } Ok(()) @@ -359,7 +358,14 @@ impl<'tcx> Stacks { } /// Hooks and glue -impl AllocationExtra for Stacks { +impl AllocationExtra for Stacks { + #[inline(always)] + fn memory_allocated<'tcx>(size: Size, _extra: &()) -> Self { + Stacks { + stacks: RefCell::new(RangeMap::new(size, Stack::default())) + } + } + #[inline(always)] fn memory_read<'tcx>( alloc: &Allocation,