Merge pull request #468 from RalfJung/pointer-provenance
update for ptr provenance
This commit is contained in:
commit
616645255a
@ -1 +1 @@
|
||||
nightly-2018-10-10
|
||||
nightly-2018-10-11
|
||||
|
@ -252,7 +252,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
||||
_ => {
|
||||
// Do it in memory
|
||||
let mplace = self.force_allocation(dest)?;
|
||||
assert!(mplace.extra.is_none());
|
||||
assert!(mplace.meta.is_none());
|
||||
self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?;
|
||||
}
|
||||
}
|
||||
@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
||||
_ => {
|
||||
// Do it in memory
|
||||
let mplace = self.force_allocation(dest)?;
|
||||
assert!(mplace.extra.is_none());
|
||||
assert!(mplace.meta.is_none());
|
||||
self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?;
|
||||
}
|
||||
}
|
||||
|
27
src/lib.rs
27
src/lib.rs
@ -13,6 +13,9 @@ extern crate rustc_mir;
|
||||
extern crate rustc_target;
|
||||
extern crate syntax;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
|
||||
use rustc::ty::layout::{TyLayout, LayoutOf, Size};
|
||||
use rustc::hir::def_id::DefId;
|
||||
@ -21,11 +24,10 @@ use rustc::mir;
|
||||
use syntax::ast::Mutability;
|
||||
use syntax::attr;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use rustc::mir::interpret::*;
|
||||
pub use rustc_mir::interpret::*;
|
||||
pub use rustc_mir::interpret;
|
||||
pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity
|
||||
|
||||
mod fn_call;
|
||||
mod operator;
|
||||
@ -34,6 +36,7 @@ mod helpers;
|
||||
mod tls;
|
||||
mod locks;
|
||||
mod range_map;
|
||||
mod mono_hash_map;
|
||||
|
||||
use fn_call::EvalContextExt as MissingFnsEvalContextExt;
|
||||
use operator::EvalContextExt as OperatorEvalContextExt;
|
||||
@ -41,6 +44,7 @@ use intrinsic::EvalContextExt as IntrinsicEvalContextExt;
|
||||
use tls::{EvalContextExt as TlsEvalContextExt, TlsData};
|
||||
use range_map::RangeMap;
|
||||
use helpers::FalibleScalarExt;
|
||||
use mono_hash_map::MonoHashMap;
|
||||
|
||||
pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
@ -231,8 +235,11 @@ pub struct Evaluator<'tcx> {
|
||||
impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
||||
type MemoryData = ();
|
||||
type MemoryKinds = MiriMemoryKind;
|
||||
type PointerTag = (); // still WIP
|
||||
|
||||
const MUT_STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::MutStatic);
|
||||
type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<()>)>;
|
||||
|
||||
const STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::MutStatic);
|
||||
const ENFORCE_VALIDITY: bool = false; // this is still WIP
|
||||
|
||||
/// Returns Ok() when the function was handled, fail otherwise
|
||||
@ -308,7 +315,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
||||
fn find_foreign_static(
|
||||
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
) -> EvalResult<'tcx, &'tcx Allocation> {
|
||||
) -> 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") {
|
||||
Some(name) => name.as_str(),
|
||||
@ -319,14 +326,13 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
||||
"__cxa_thread_atexit_impl" => {
|
||||
// This should be all-zero, pointer-sized
|
||||
let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize];
|
||||
let alloc = Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align);
|
||||
tcx.intern_const_alloc(alloc)
|
||||
Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align)
|
||||
}
|
||||
_ => return err!(Unimplemented(
|
||||
format!("can't access foreign static: {}", link_name),
|
||||
)),
|
||||
};
|
||||
Ok(alloc)
|
||||
Ok(Cow::Owned(alloc))
|
||||
}
|
||||
|
||||
fn validation_op(
|
||||
@ -344,4 +350,11 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
||||
// We are not interested in detecting loops
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn static_with_default_tag(
|
||||
alloc: &'_ Allocation
|
||||
) -> Cow<'_, Allocation<Self::PointerTag>> {
|
||||
let alloc = alloc.clone();
|
||||
Cow::Owned(alloc)
|
||||
}
|
||||
}
|
||||
|
91
src/mono_hash_map.rs
Normal file
91
src/mono_hash_map.rs
Normal file
@ -0,0 +1,91 @@
|
||||
//! This is a "monotonic HashMap": A HashMap that, when shared, can be pushed to but not
|
||||
//! otherwise mutated. We also Box items in the map. This means we can safely provide
|
||||
//! shared references into existing items in the HashMap, because they will not be dropped
|
||||
//! (from being removed) or moved (because they are boxed).
|
||||
//! The API is is completely tailored to what `memory.rs` needs. It is still in
|
||||
//! a separate file to minimize the amount of code that has to care about the unsafety.
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::cell::RefCell;
|
||||
use std::hash::Hash;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
||||
use super::AllocMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MonoHashMap<K: Hash + Eq, V>(RefCell<FxHashMap<K, Box<V>>>);
|
||||
|
||||
impl<K: Hash + Eq, V> Default for MonoHashMap<K, V> {
|
||||
fn default() -> Self {
|
||||
MonoHashMap(RefCell::new(Default::default()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq, V> AllocMap<K, V> for MonoHashMap<K, V> {
|
||||
#[inline(always)]
|
||||
fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
|
||||
where K: Borrow<Q>
|
||||
{
|
||||
self.0.get_mut().contains_key(k)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn insert(&mut self, k: K, v: V) -> Option<V>
|
||||
{
|
||||
self.0.get_mut().insert(k, Box::new(v)).map(|x| *x)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
|
||||
where K: Borrow<Q>
|
||||
{
|
||||
self.0.get_mut().remove(k).map(|x| *x)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
|
||||
self.0.borrow()
|
||||
.iter()
|
||||
.filter_map(move |(k, v)| f(k, &*v))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// The most interesting method: Providing a shared ref without
|
||||
/// holding the `RefCell` open, and inserting new data if the key
|
||||
/// is not used yet.
|
||||
/// `vacant` is called if the key is not found in the map;
|
||||
/// if it returns a reference, that is used directly, if it
|
||||
/// returns owned data, that is put into the map and returned.
|
||||
#[inline(always)]
|
||||
fn get_or<E>(
|
||||
&self,
|
||||
k: K,
|
||||
vacant: impl FnOnce() -> Result<V, E>
|
||||
) -> Result<&V, E> {
|
||||
let val: *const V = match self.0.borrow_mut().entry(k) {
|
||||
Entry::Occupied(entry) => &**entry.get(),
|
||||
Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)),
|
||||
};
|
||||
// This is safe because `val` points into a `Box`, that we know will not move and
|
||||
// will also not be dropped as long as the shared reference `self` is live.
|
||||
unsafe { Ok(&*val) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_mut_or<E>(
|
||||
&mut self,
|
||||
k: K,
|
||||
vacant: impl FnOnce() -> Result<V, E>
|
||||
) -> Result<&mut V, E>
|
||||
{
|
||||
match self.0.get_mut().entry(k) {
|
||||
Entry::Occupied(e) => Ok(e.into_mut()),
|
||||
Entry::Vacant(e) => {
|
||||
let v = vacant()?;
|
||||
Ok(e.insert(Box::new(v)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user