Use enum instead of boolean

This commit is contained in:
Oliver Schneider 2017-07-13 17:25:17 +02:00
parent 70a914cd34
commit eb01c3fdd2
No known key found for this signature in database
GPG Key ID: 1D5CB4FC597C3004
6 changed files with 61 additions and 51 deletions

View File

@ -1,5 +1,6 @@
use rustc::traits::Reveal;
use rustc::ty::{self, TyCtxt, Ty, Instance};
use syntax::ast::Mutability;
use error::{EvalError, EvalResult};
use lvalue::{Global, GlobalId, Lvalue};
@ -25,7 +26,12 @@ pub fn eval_body_as_primval<'a, 'tcx>(
ecx.tcx,
ty::ParamEnv::empty(Reveal::All),
mir.span);
let cleanup = StackPopCleanup::MarkStatic(mutable);
let mutability = if mutable {
Mutability::Mutable
} else {
Mutability::Immutable
};
let cleanup = StackPopCleanup::MarkStatic(mutability);
let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
trace!("pushing stack frame for global: {}", name);
ecx.push_stack_frame(

View File

@ -12,7 +12,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder};
use rustc::traits;
use rustc_data_structures::indexed_vec::Idx;
use syntax::codemap::{self, DUMMY_SP, Span};
use syntax::ast;
use syntax::ast::{self, Mutability};
use syntax::abi::Abi;
use error::{EvalError, EvalResult};
@ -98,8 +98,7 @@ pub enum StackPopCleanup {
/// isn't modifyable afterwards in case of constants.
/// In case of `static mut`, mark the memory to ensure it's never marked as immutable through
/// references or deallocated
/// The bool decides whether the value is mutable (true) or not (false)
MarkStatic(bool),
MarkStatic(Mutability),
/// A regular stackframe added due to a function call will need to get forwarded to the next
/// block
Goto(mir::BasicBlock),
@ -354,23 +353,23 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
Value::ByRef(ptr, _aligned) =>
// Alignment does not matter for this call
self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, !mutable)?,
self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, mutable)?,
Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val {
self.memory.mark_inner_allocation(ptr.alloc_id, !mutable)?;
self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
},
Value::ByValPair(val1, val2) => {
if let PrimVal::Ptr(ptr) = val1 {
self.memory.mark_inner_allocation(ptr.alloc_id, !mutable)?;
self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
}
if let PrimVal::Ptr(ptr) = val2 {
self.memory.mark_inner_allocation(ptr.alloc_id, !mutable)?;
self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
}
},
}
// see comment on `initialized` field
assert!(!global_value.initialized);
global_value.initialized = true;
assert!(global_value.mutable);
assert_eq!(global_value.mutable, Mutability::Mutable);
global_value.mutable = mutable;
} else {
bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue);
@ -1023,7 +1022,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
Lvalue::Ptr { .. } => lvalue,
Lvalue::Global(cid) => {
let global_val = *self.globals.get(&cid).expect("global not cached");
let global_val = self.globals.get(&cid).expect("global not cached").clone();
match global_val.value {
Value::ByRef(ptr, aligned) =>
Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None },
@ -1033,7 +1032,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.write_value_to_ptr(global_val.value, ptr.into(), global_val.ty)?;
// see comment on `initialized` field
if global_val.initialized {
self.memory.mark_static_initalized(ptr.alloc_id, !global_val.mutable)?;
self.memory.mark_static_initalized(ptr.alloc_id, global_val.mutable)?;
}
let lval = self.globals.get_mut(&cid).expect("already checked");
*lval = Global {
@ -1109,8 +1108,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
match dest {
Lvalue::Global(cid) => {
let dest = *self.globals.get_mut(&cid).expect("global should be cached");
if !dest.mutable {
let dest = self.globals.get_mut(&cid).expect("global should be cached").clone();
if dest.mutable == Mutability::Immutable {
return Err(EvalError::ModifiedConstantMemory);
}
let write_dest = |this: &mut Self, val| {
@ -1595,8 +1594,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
pub fn modify_global<F>(&mut self, cid: GlobalId<'tcx>, f: F) -> EvalResult<'tcx>
where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
{
let mut val = *self.globals.get(&cid).expect("global not cached");
if !val.mutable {
let mut val = self.globals.get(&cid).expect("global not cached").clone();
if val.mutable == Mutability::Immutable {
return Err(EvalError::ModifiedConstantMemory);
}
val.value = f(self, val.value)?;

View File

@ -2,6 +2,7 @@ use rustc::mir;
use rustc::ty::layout::{Size, Align};
use rustc::ty::{self, Ty};
use rustc_data_structures::indexed_vec::Idx;
use syntax::ast::Mutability;
use error::{EvalError, EvalResult};
use eval_context::EvalContext;
@ -51,7 +52,7 @@ pub struct GlobalId<'tcx> {
pub(super) promoted: Option<mir::Promoted>,
}
#[derive(Copy, Clone, Debug)]
#[derive(Clone, Debug)]
pub struct Global<'tcx> {
pub(super) value: Value,
/// Only used in `force_allocation` to ensure we don't mark the memory
@ -59,7 +60,7 @@ pub struct Global<'tcx> {
/// global which initially is `Value::ByVal(PrimVal::Undef)` and gets
/// lifted to an allocation before the static is fully initialized
pub(super) initialized: bool,
pub(super) mutable: bool,
pub(super) mutable: Mutability,
pub(super) ty: Ty<'tcx>,
}
@ -113,13 +114,13 @@ impl<'tcx> Global<'tcx> {
pub(super) fn uninitialized(ty: Ty<'tcx>) -> Self {
Global {
value: Value::ByVal(PrimVal::Undef),
mutable: true,
mutable: Mutability::Mutable,
ty,
initialized: false,
}
}
pub(super) fn initialized(ty: Ty<'tcx>, value: Value, mutable: bool) -> Self {
pub(super) fn initialized(ty: Ty<'tcx>, value: Value, mutable: Mutability) -> Self {
Global {
value,
mutable,

View File

@ -4,6 +4,7 @@ use std::{fmt, iter, ptr, mem, io};
use rustc::ty;
use rustc::ty::layout::{self, TargetDataLayout};
use syntax::ast::Mutability;
use error::{EvalError, EvalResult};
use value::{PrimVal, self, Pointer};
@ -35,7 +36,7 @@ pub struct Allocation {
/// The alignment of the allocation to detect unaligned reads.
pub align: u64,
/// Whether the allocation may be modified.
pub mutable: bool,
pub mutable: Mutability,
/// Use the `mark_static_initalized` method of `Memory` to ensure that an error occurs, if the memory of this
/// allocation is modified or deallocated in the future.
/// Helps guarantee that stack allocations aren't deallocated via `rust_deallocate`
@ -50,6 +51,11 @@ pub enum Kind {
C,
/// Error if deallocated except during a stack pop
Stack,
/// Static in the process of being initialized.
/// The difference is important: An immutable static referring to a
/// mutable initialized static will freeze immutably and would not
/// be able to distinguish already initialized statics from uninitialized ones
UninitializedStatic,
/// May never be deallocated
Static,
/// Part of env var emulation
@ -189,7 +195,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
let ptr = self.allocate(bytes.len() as u64, 1, Kind::Static)?;
self.write_bytes(PrimVal::Ptr(ptr), bytes)?;
self.mark_static_initalized(ptr.alloc_id, true)?;
self.mark_static_initalized(ptr.alloc_id, Mutability::Mutable)?;
self.literal_alloc_cache.insert(bytes.to_vec(), ptr.alloc_id);
Ok(ptr)
}
@ -213,7 +219,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
undef_mask: UndefMask::new(size),
align,
kind,
mutable: true,
mutable: Mutability::Mutable,
};
let id = self.next_id;
self.next_id.0 += 1;
@ -404,7 +410,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation> {
match self.alloc_map.get_mut(&id) {
Some(alloc) => if alloc.mutable {
Some(alloc) => if alloc.mutable == Mutability::Mutable {
Ok(alloc)
} else {
Err(EvalError::ModifiedConstantMemory)
@ -477,8 +483,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
}
let immutable = match (alloc.kind, alloc.mutable) {
(Kind::Static, true) => " (static mut)",
(Kind::Static, false) => " (immutable)",
(Kind::UninitializedStatic, _) => " (static in the process of initialization)",
(Kind::Static, Mutability::Mutable) => " (static mut)",
(Kind::Static, Mutability::Immutable) => " (immutable)",
(Kind::Env, _) => " (env var)",
(Kind::C, _) => " (malloc)",
(Kind::Rust, _) => " (heap)",
@ -584,31 +591,23 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
}
/// mark an allocation pointed to by a static as static and initialized
pub fn mark_inner_allocation(&mut self, alloc: AllocId, make_immutable: bool) -> EvalResult<'tcx> {
pub fn mark_inner_allocation(&mut self, alloc: AllocId, mutability: Mutability) -> EvalResult<'tcx> {
// relocations into other statics are not "inner allocations"
if !self.static_alloc.contains(&alloc) {
self.mark_static_initalized(alloc, make_immutable)?;
self.mark_static_initalized(alloc, mutability)?;
}
Ok(())
}
/// mark an allocation as static and initialized, either mutable or not
pub fn mark_static_initalized(&mut self, alloc_id: AllocId, make_immutable: bool) -> EvalResult<'tcx> {
trace!("mark_static_initalized {:?}, make_immutable: {:?}", alloc_id, make_immutable);
pub fn mark_static_initalized(&mut self, alloc_id: AllocId, mutability: Mutability) -> EvalResult<'tcx> {
trace!("mark_static_initalized {:?}, mutability: {:?}", alloc_id, mutability);
// do not use `self.get_mut(alloc_id)` here, because we might have already marked a
// sub-element or have circular pointers (e.g. `Rc`-cycles)
let relocations = match self.alloc_map.get_mut(&alloc_id) {
Some(&mut Allocation { kind: Kind::Static, ref mut mutable, .. }) => {
if make_immutable {
*mutable = false;
}
return Ok(());
},
Some(&mut Allocation { ref mut relocations, ref mut kind, ref mut mutable, .. }) => {
Some(&mut Allocation { ref mut relocations, kind: ref mut kind @ Kind::UninitializedStatic, ref mut mutable, .. }) => {
*kind = Kind::Static;
if make_immutable {
*mutable = false;
}
*mutable = mutability;
// take out the relocations vector to free the borrow on self, so we can call
// mark recursively
mem::replace(relocations, Default::default())
@ -618,7 +617,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
};
// recurse into inner allocations
for &alloc in relocations.values() {
self.mark_inner_allocation(alloc, make_immutable)?;
self.mark_inner_allocation(alloc, mutability)?;
}
// put back the relocations
self.alloc_map.get_mut(&alloc_id).expect("checked above").relocations = relocations;

View File

@ -15,6 +15,7 @@ use eval_context::{EvalContext, StackPopCleanup};
use lvalue::{Global, GlobalId, Lvalue};
use value::{Value, PrimVal};
use syntax::codemap::Span;
use syntax::ast::Mutability;
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
@ -162,7 +163,7 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
def_id: DefId,
substs: &'tcx subst::Substs<'tcx>,
span: Span,
shared: bool,
mutability: Mutability,
) {
let instance = self.ecx.resolve_associated_const(def_id, substs);
let cid = GlobalId { instance, promoted: None };
@ -171,18 +172,22 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
}
if self.ecx.tcx.has_attr(def_id, "linkage") {
trace!("Initializing an extern global with NULL");
self.ecx.globals.insert(cid, Global::initialized(self.ecx.tcx.type_of(def_id), Value::ByVal(PrimVal::Bytes(0)), !shared));
self.ecx.globals.insert(cid, Global::initialized(self.ecx.tcx.type_of(def_id), Value::ByVal(PrimVal::Bytes(0)), mutability));
return;
}
self.try(|this| {
let mir = this.ecx.load_mir(instance.def)?;
this.ecx.globals.insert(cid, Global::uninitialized(mir.return_ty));
let mutable = !shared ||
!mir.return_ty.is_freeze(
let internally_mutable = !mir.return_ty.is_freeze(
this.ecx.tcx,
ty::ParamEnv::empty(Reveal::All),
span);
let cleanup = StackPopCleanup::MarkStatic(mutable);
let mutability = if mutability == Mutability::Mutable || internally_mutable {
Mutability::Mutable
} else {
Mutability::Immutable
};
let cleanup = StackPopCleanup::MarkStatic(mutability);
let name = ty::tls::with(|tcx| tcx.item_path_str(def_id));
trace!("pushing stack frame for global: {}", name);
this.ecx.push_stack_frame(
@ -214,7 +219,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
// already computed by rustc
mir::Literal::Value { .. } => {}
mir::Literal::Item { def_id, substs } => {
self.global_item(def_id, substs, constant.span, true);
self.global_item(def_id, substs, constant.span, Mutability::Immutable);
},
mir::Literal::Promoted { index } => {
let cid = GlobalId {
@ -233,7 +238,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
constant.span,
mir,
Lvalue::Global(cid),
StackPopCleanup::MarkStatic(false),
StackPopCleanup::MarkStatic(Mutability::Immutable),
)
});
}
@ -254,7 +259,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) {
if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
if let hir::ItemStatic(_, m, _) = *node {
self.global_item(def_id, substs, span, m == hir::MutImmutable);
self.global_item(def_id, substs, span, if m == hir::MutMutable { Mutability::Mutable } else { Mutability::Immutable });
return;
} else {
bug!("static def id doesn't point to static");
@ -265,7 +270,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
} else {
let def = self.ecx.tcx.describe_def(def_id).expect("static not found");
if let hir::def::Def::Static(_, mutable) = def {
self.global_item(def_id, substs, span, !mutable);
self.global_item(def_id, substs, span, if mutable { Mutability::Mutable } else { Mutability::Immutable });
} else {
bug!("static found but isn't a static: {:?}", def);
}

View File

@ -8,7 +8,7 @@ use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty};
use syntax::codemap::DUMMY_SP;
use syntax::ast;
use syntax::ast::{self, Mutability};
use error::{EvalResult, EvalError};
@ -68,7 +68,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
}
self.memory.mark_static_initalized(vtable.alloc_id, true)?;
self.memory.mark_static_initalized(vtable.alloc_id, Mutability::Mutable)?;
Ok(vtable)
}