Skip to content

update for ptr provenance #468

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nightly-2018-10-10
nightly-2018-10-11
4 changes: 2 additions & 2 deletions src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
}
}
Expand Down Expand Up @@ -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)?;
}
}
Expand Down
27 changes: 20 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -34,13 +36,15 @@ mod helpers;
mod tls;
mod locks;
mod range_map;
mod mono_hash_map;

use fn_call::EvalContextExt as MissingFnsEvalContextExt;
use operator::EvalContextExt as OperatorEvalContextExt;
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>,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand All @@ -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(
Expand All @@ -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 changes: 91 additions & 0 deletions src/mono_hash_map.rs
Original file line number Diff line number Diff line change
@@ -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)))
}
}
}
}