Merge pull request #468 from RalfJung/pointer-provenance

update for ptr provenance
This commit is contained in:
Oliver S̶c̶h̶n̶e̶i̶d̶e̶r Scherer 2018-10-11 09:15:35 +02:00 committed by GitHub
commit 616645255a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 114 additions and 10 deletions

View File

@ -1 +1 @@
nightly-2018-10-10
nightly-2018-10-11

View File

@ -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)?;
}
}

View File

@ -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
View 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)))
}
}
}
}