--- /dev/null
+use std::cell::RefCell;
+
+use rustc::mir::interpret::AllocId;
+
+pub type MemoryState = RefCell<GlobalState>;
+
+#[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)
+ }
+ }
+}
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;
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};
}
}
+ ecx.memory_mut().extra.seed = config.seed.clone();
+
assert!(args.next().is_none(), "start lang item has more arguments than expected");
Ok(ecx)
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<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<Tag, Self::AllocExtra>)>;
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<Tag, Self::AllocExtra> = Allocation {
bytes: alloc.bytes,
relocations: Relocations::from_presorted(
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)
}
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)]
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)]
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<Self::PointerTag>> {
+ 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<Self::PointerTag>,
+ 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())
}
}
--- /dev/null
+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<u64>,
+}
+
+#[derive(Debug, Clone,)]
+pub struct AllocExtra {
+ pub stacks: stacked_borrows::Stacks,
+ pub base_addr: RefCell<Option<u64>>,
+}
+
+impl AllocationExtra<Tag> for AllocExtra {
+ #[inline(always)]
+ fn memory_read<'tcx>(
+ alloc: &Allocation<Tag, AllocExtra>,
+ ptr: Pointer<Tag>,
+ 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<Tag, AllocExtra>,
+ ptr: Pointer<Tag>,
+ 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<Tag, AllocExtra>,
+ ptr: Pointer<Tag>,
+ 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)
+ })
+ }
+}
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;
/// 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,
/// 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,
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<Tag>,
size: Size,
pub fn new_allocation(
id: AllocId,
size: Size,
- extra: MemoryState,
+ extra: MemoryState,
kind: MemoryKind<MiriMemoryKind>,
) -> (Self, Tag) {
let (tag, perm) = match kind {
}
}
-impl AllocationExtra<Tag> for Stacks {
- #[inline(always)]
- fn memory_read<'tcx>(
- alloc: &Allocation<Tag, Stacks>,
- ptr: Pointer<Tag>,
- 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<Tag, Stacks>,
- ptr: Pointer<Tag>,
- 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<Tag, Stacks>,
- ptr: Pointer<Tag>,
- 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> {}
// 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)
})
}
// 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.
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,
}