From: Christian Poveda Date: Thu, 20 Jun 2019 19:21:47 +0000 (-0500) Subject: Implement intptrcast methods X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=fd3a291db49fbb6a0198f8bb05990f9163cc1f66;p=rust.git Implement intptrcast methods --- diff --git a/src/intptrcast.rs b/src/intptrcast.rs new file mode 100644 index 00000000000..3e07f54fbd3 --- /dev/null +++ b/src/intptrcast.rs @@ -0,0 +1,20 @@ +use std::cell::RefCell; + +use rustc::mir::interpret::AllocId; + +pub type MemoryState = RefCell; + +#[derive(Clone, Debug)] +pub struct GlobalState { + pub vec: Vec<(u64, AllocId)>, + pub addr: u64, +} + +impl Default for GlobalState { + fn default() -> Self { + GlobalState { + vec: Vec::default(), + addr: 2u64.pow(16) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 9072f141f89..f61abea62e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,9 +20,12 @@ mod range_map; mod mono_hash_map; mod stacked_borrows; +mod intptrcast; +mod memory; use std::collections::HashMap; use std::borrow::Cow; +use std::cell::RefCell; use std::rc::Rc; use rand::rngs::StdRng; @@ -48,6 +51,7 @@ pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; +use crate::memory::AllocExtra; // Used by priroda. pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item}; @@ -206,6 +210,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } } + ecx.memory_mut().extra.seed = config.seed.clone(); + assert!(args.next().is_none(), "start lang item has more arguments than expected"); Ok(ecx) @@ -386,8 +392,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = stacked_borrows::CallId; - type MemoryExtra = stacked_borrows::MemoryState; - type AllocExtra = stacked_borrows::Stacks; + type MemoryExtra = memory::MemoryState; + type AllocExtra = memory::AllocExtra; type PointerTag = Tag; type MemoryMap = MonoHashMap, Allocation)>; @@ -515,14 +521,14 @@ fn tag_allocation<'b>( let (extra, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra), + Rc::clone(&memory.extra.stacked), kind, ); if kind != MiriMemoryKind::Static.into() { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. } - let mut memory_extra = memory.extra.borrow_mut(); + let mut memory_extra = memory.extra.stacked.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -535,7 +541,10 @@ fn tag_allocation<'b>( undef_mask: alloc.undef_mask, align: alloc.align, mutability: alloc.mutability, - extra, + extra: AllocExtra { + stacks: extra, + base_addr: RefCell::new(None), + }, }; (Cow::Owned(alloc), base_tag) } @@ -545,7 +554,7 @@ fn tag_static_base_pointer( id: AllocId, memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - memory.extra.borrow_mut().static_base_ptr(id) + memory.extra.stacked.borrow_mut().static_base_ptr(id) } #[inline(always)] @@ -570,7 +579,7 @@ fn retag( fn stack_push( ecx: &mut InterpretCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory().extra.borrow_mut().new_call()) + Ok(ecx.memory().extra.stacked.borrow_mut().new_call()) } #[inline(always)] @@ -578,6 +587,76 @@ fn stack_pop( ecx: &mut InterpretCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { - Ok(ecx.memory().extra.borrow_mut().end_call(extra)) + Ok(ecx.memory().extra.stacked.borrow_mut().end_call(extra)) + } + + fn int_to_ptr( + int: u64, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, Pointer> { + if int == 0 { + return err!(InvalidNullPointerUsage); + } + + if memory.extra.seed.is_none() { + return err!(ReadBytesAsPointer); + } + + let extra = memory.extra.intptrcast.borrow(); + + match extra.vec.binary_search_by_key(&int, |(int, _)| *int) { + Ok(pos) => { + let (_, alloc_id) = extra.vec[pos]; + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) + } + Err(pos) => { + if pos > 0 { + let (glb, alloc_id) = extra.vec[pos - 1]; + let offset = int - glb; + if offset <= memory.get(alloc_id)?.bytes.len() as u64 { + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) + } else { + return err!(DanglingPointerDeref); + } + } else { + return err!(DanglingPointerDeref); + } + } + } + } + + fn ptr_to_int( + ptr: Pointer, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, u64> { + if memory.extra.seed.is_none() { + return err!(ReadPointerAsBytes); + } + + let mut extra = memory.extra.intptrcast.borrow_mut(); + + let alloc = memory.get(ptr.alloc_id)?; + + let base_addr = match alloc.extra.base_addr.borrow().clone() { + Some(base_addr) => base_addr, + None => { + let base_addr = extra.addr; + extra.addr += alloc.bytes.len() as u64; + + *alloc.extra.base_addr.borrow_mut() = Some(base_addr); + + let elem = (base_addr, ptr.alloc_id); + + if let Err(pos) = extra.vec.binary_search(&elem) { + extra.vec.insert(pos, elem); + } else { + return err!(Unreachable); + } + + base_addr + } + }; + + Ok(base_addr + ptr.offset.bytes()) } } diff --git a/src/memory.rs b/src/memory.rs new file mode 100644 index 00000000000..13ffd859ade --- /dev/null +++ b/src/memory.rs @@ -0,0 +1,60 @@ +use std::cell::RefCell; + +use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult}; +use rustc_target::abi::Size; + +use crate::{stacked_borrows, intptrcast}; +use crate::stacked_borrows::{Tag, AccessKind}; + +#[derive(Default, Clone, Debug)] +pub struct MemoryState { + pub stacked: stacked_borrows::MemoryState, + pub intptrcast: intptrcast::MemoryState, + pub seed: Option, +} + +#[derive(Debug, Clone,)] +pub struct AllocExtra { + pub stacks: stacked_borrows::Stacks, + pub base_addr: RefCell>, +} + +impl AllocationExtra for AllocExtra { + #[inline(always)] + fn memory_read<'tcx>( + alloc: &Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + alloc.extra.stacks.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Read, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + fn memory_written<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + alloc.extra.stacks.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Write, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + fn memory_deallocated<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + alloc.extra.stacks.for_each(ptr, size, |stack, global| { + stack.dealloc(ptr.tag, global) + }) + } +} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f7617676701..ea70c28709c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,8 +10,8 @@ use crate::{ InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, CheckInAllocMsg, - Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, CheckInAllocMsg, Pointer, Immediate, ImmTy, + PlaceTy, MPlaceTy, }; pub type PtrId = NonZeroU64; @@ -286,7 +286,7 @@ fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> Inter /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - fn access( + pub(crate) fn access( &mut self, access: AccessKind, tag: Tag, @@ -336,7 +336,7 @@ fn access( /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - fn dealloc( + pub(crate) fn dealloc( &mut self, tag: Tag, global: &GlobalState, @@ -429,14 +429,15 @@ fn new( let stack = Stack { borrows: vec![item], }; + Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), - global: extra, + global: extra, } } /// Call `f` on every stack in the range. - fn for_each( + pub(crate) fn for_each( &self, ptr: Pointer, size: Size, @@ -456,7 +457,7 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: MemoryState, + extra: MemoryState, kind: MemoryKind, ) -> (Self, Tag) { let (tag, perm) = match kind { @@ -477,46 +478,6 @@ pub fn new_allocation( } } -impl AllocationExtra for Stacks { - #[inline(always)] - fn memory_read<'tcx>( - alloc: &Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Read, ptr.tag, global)?; - Ok(()) - }) - } - - #[inline(always)] - fn memory_written<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Write, ptr.tag, global)?; - Ok(()) - }) - } - - #[inline(always)] - fn memory_deallocated<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.for_each(ptr, size, |stack, global| { - stack.dealloc(ptr.tag, global) - }) - } -} - /// Retagging/reborrowing. There is some policy in here, such as which permissions /// to grant for which references, and when to add protectors. impl<'mir, 'tcx> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -553,14 +514,14 @@ fn reborrow( // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.for_each(cur_ptr, size, |stack, global| { + alloc.extra.stacks.for_each(cur_ptr, size, |stack, global| { stack.grant(cur_ptr.tag, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.for_each(ptr, size, |stack, global| { + alloc.extra.stacks.for_each(ptr, size, |stack, global| { stack.grant(ptr.tag, item, global) }) } @@ -587,7 +548,7 @@ fn retag_reference( // Compute new borrow. let new_tag = match kind { RefKind::Raw { .. } => Tag::Untagged, - _ => Tag::Tagged(this.memory().extra.borrow_mut().new_ptr()), + _ => Tag::Tagged(this.memory().extra.stacked.borrow_mut().new_ptr()), }; // Reborrow. @@ -621,7 +582,7 @@ fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call - // they were passed in to; that's just not the case for boxes. + // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), _ => None, }