提交 5328c5d1 编写于 作者: O Oliver Schneider 提交者: GitHub

Merge pull request #245 from oli-obk/funky_allocs

Ensure that it is not possible to explicitly free stack memory
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(
......
......@@ -2,7 +2,7 @@
use std::fmt;
use rustc::mir;
use rustc::ty::{FnSig, Ty, layout};
use memory::MemoryPointer;
use memory::{MemoryPointer, Kind};
use rustc_const_math::ConstMathErr;
use syntax::codemap::Span;
......@@ -12,6 +12,7 @@ pub enum EvalError<'tcx> {
NoMirFor(String),
UnterminatedCString(MemoryPointer),
DanglingPointerDeref,
DoubleFree,
InvalidMemoryAccess,
InvalidFunctionPointer,
InvalidBool,
......@@ -56,8 +57,8 @@ pub enum EvalError<'tcx> {
AssumptionNotHeld,
InlineAsm,
TypeNotPrimitive(Ty<'tcx>),
ReallocatedStaticMemory,
DeallocatedStaticMemory,
ReallocatedWrongMemoryKind(Kind, Kind),
DeallocatedWrongMemoryKind(Kind, Kind),
ReallocateNonBasePtr,
DeallocateNonBasePtr,
IncorrectAllocationInformation,
......@@ -84,6 +85,8 @@ fn description(&self) -> &str {
"tried to access memory through an invalid pointer",
DanglingPointerDeref =>
"dangling pointer was dereferenced",
DoubleFree =>
"tried to deallocate dangling pointer",
InvalidFunctionPointer =>
"tried to use an integer pointer or a dangling pointer as a function pointer",
InvalidBool =>
......@@ -148,10 +151,10 @@ fn description(&self) -> &str {
"miri does not support inline assembly",
TypeNotPrimitive(_) =>
"expected primitive type, got nonprimitive",
ReallocatedStaticMemory =>
"tried to reallocate static memory",
DeallocatedStaticMemory =>
"tried to deallocate static memory",
ReallocatedWrongMemoryKind(_, _) =>
"tried to reallocate memory from one kind to another",
DeallocatedWrongMemoryKind(_, _) =>
"tried to deallocate memory of the wrong kind",
ReallocateNonBasePtr =>
"tried to reallocate with a pointer not to the beginning of an existing object",
DeallocateNonBasePtr =>
......@@ -198,6 +201,10 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got),
ArrayIndexOutOfBounds(span, len, index) =>
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
ReallocatedWrongMemoryKind(old, new) =>
write!(f, "tried to reallocate memory from {:?} to {:?}", old, new),
DeallocatedWrongMemoryKind(old, new) =>
write!(f, "tried to deallocate {:?} memory but gave {:?} as the kind", old, new),
Math(span, ref err) =>
write!(f, "{:?} at {:?}", err, span),
Intrinsic(ref err) =>
......
......@@ -12,7 +12,7 @@
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),
......@@ -154,7 +153,7 @@ pub fn alloc_ptr_with_substs(
) -> EvalResult<'tcx, MemoryPointer> {
let size = self.type_size_with_substs(ty, substs)?.expect("cannot alloc memory for unsized type");
let align = self.type_align_with_substs(ty, substs)?;
self.memory.allocate(size, align)
self.memory.allocate(size, align, ::memory::Kind::Stack)
}
pub fn memory(&self) -> &Memory<'a, 'tcx> {
......@@ -370,7 +369,7 @@ pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
// 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);
......@@ -414,11 +413,13 @@ pub fn deallocate_local(&mut self, local: Option<Value>) -> EvalResult<'tcx> {
trace!("deallocating local");
let ptr = ptr.to_ptr()?;
self.memory.dump_alloc(ptr.alloc_id);
match self.memory.deallocate(ptr, None) {
// We could alternatively check whether the alloc_id is static before calling
// deallocate, but this is much simpler and is probably the rare case.
Ok(()) | Err(EvalError::DeallocatedStaticMemory) => {},
other => return other,
match self.memory.get(ptr.alloc_id)?.kind {
// for a constant like `const FOO: &i32 = &1;` the local containing
// the `1` is referred to by the global. We transitively marked everything
// the global refers to as static itself, so we don't free it here
::memory::Kind::Static => {}
::memory::Kind::Stack => self.memory.deallocate(ptr, None, ::memory::Kind::Stack)?,
other => bug!("local contained non-stack memory: {:?}", other),
}
};
Ok(())
......@@ -693,11 +694,13 @@ pub(super) fn eval_rvalue_into_lvalue(
return Err(EvalError::NeedsRfc("\"heap\" allocations".to_string()));
}
// FIXME: call the `exchange_malloc` lang item if available
if self.type_size(ty)?.expect("box only works with sized types") == 0 {
let size = self.type_size(ty)?.expect("box only works with sized types");
if size == 0 {
let align = self.type_align(ty)?;
self.write_primval(dest, PrimVal::Bytes(align.into()), dest_ty)?;
} else {
let ptr = self.alloc_ptr(ty)?;
let align = self.type_align(ty)?;
let ptr = self.memory.allocate(size, align, ::memory::Kind::Rust)?;
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
}
}
......@@ -1022,7 +1025,7 @@ pub(super) fn force_allocation(
}
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 },
......@@ -1108,8 +1111,8 @@ pub(super) fn write_value(
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| {
......@@ -1594,8 +1597,8 @@ pub(super) fn dump_local(&self, lvalue: Lvalue<'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)?;
......@@ -1686,7 +1689,7 @@ fn run_main<'a, 'tcx: 'a>(
}
// Return value
let ret_ptr = ecx.memory.allocate(ecx.tcx.data_layout.pointer_size.bytes(), ecx.tcx.data_layout.pointer_align.abi())?;
let ret_ptr = ecx.memory.allocate(ecx.tcx.data_layout.pointer_size.bytes(), ecx.tcx.data_layout.pointer_align.abi(), ::memory::Kind::Stack)?;
cleanup_ptr = Some(ret_ptr);
// Push our stack frame
......@@ -1728,7 +1731,7 @@ fn run_main<'a, 'tcx: 'a>(
while ecx.step()? {}
if let Some(cleanup_ptr) = cleanup_ptr {
ecx.memory.deallocate(cleanup_ptr, None)?;
ecx.memory.deallocate(cleanup_ptr, None, ::memory::Kind::Stack)?;
}
return Ok(());
}
......
......@@ -2,6 +2,7 @@
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,
......
......@@ -4,6 +4,7 @@
use rustc::ty;
use rustc::ty::layout::{self, TargetDataLayout};
use syntax::ast::Mutability;
use error::{EvalError, EvalResult};
use value::{PrimVal, self, Pointer};
......@@ -35,19 +36,30 @@ pub struct Allocation {
/// The alignment of the allocation to detect unaligned reads.
pub align: u64,
/// Whether the allocation may be modified.
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.
pub static_kind: StaticKind,
/// Helps guarantee that stack allocations aren't deallocated via `rust_deallocate`
pub kind: Kind,
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum StaticKind {
/// may be deallocated without breaking miri's invariants
NotStatic,
/// may be modified, but never deallocated
Mutable,
/// may neither be modified nor deallocated
Immutable,
pub enum Kind {
/// Error if deallocated any other way than `rust_deallocate`
Rust,
/// Error if deallocated any other way than `free`
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
Env,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
......@@ -181,14 +193,14 @@ pub fn allocate_cached(&mut self, bytes: &[u8]) -> EvalResult<'tcx, MemoryPointe
return Ok(MemoryPointer::new(alloc_id, 0));
}
let ptr = self.allocate(bytes.len() as u64, 1)?;
let ptr = self.allocate(bytes.len() as u64, 1, Kind::UninitializedStatic)?;
self.write_bytes(PrimVal::Ptr(ptr), bytes)?;
self.mark_static_initalized(ptr.alloc_id, false)?;
self.mark_static_initalized(ptr.alloc_id, Mutability::Immutable)?;
self.literal_alloc_cache.insert(bytes.to_vec(), ptr.alloc_id);
Ok(ptr)
}
pub fn allocate(&mut self, size: u64, align: u64) -> EvalResult<'tcx, MemoryPointer> {
pub fn allocate(&mut self, size: u64, align: u64, kind: Kind) -> EvalResult<'tcx, MemoryPointer> {
assert_ne!(align, 0);
assert!(align.is_power_of_two());
......@@ -206,7 +218,8 @@ pub fn allocate(&mut self, size: u64, align: u64) -> EvalResult<'tcx, MemoryPoin
relocations: BTreeMap::new(),
undef_mask: UndefMask::new(size),
align,
static_kind: StaticKind::NotStatic,
kind,
mutable: Mutability::Mutable,
};
let id = self.next_id;
self.next_id.0 += 1;
......@@ -214,49 +227,45 @@ pub fn allocate(&mut self, size: u64, align: u64) -> EvalResult<'tcx, MemoryPoin
Ok(MemoryPointer::new(id, 0))
}
// TODO(solson): Track which allocations were returned from __rust_allocate and report an error
// when reallocating/deallocating any others.
pub fn reallocate(&mut self, ptr: MemoryPointer, old_size: u64, old_align: u64, new_size: u64, new_align: u64) -> EvalResult<'tcx, MemoryPointer> {
pub fn reallocate(&mut self, ptr: MemoryPointer, old_size: u64, old_align: u64, new_size: u64, new_align: u64, kind: Kind) -> EvalResult<'tcx, MemoryPointer> {
use std::cmp::min;
// TODO(solson): Report error about non-__rust_allocate'd pointer.
if ptr.offset != 0 || self.get(ptr.alloc_id).is_err() {
return Err(EvalError::ReallocateNonBasePtr);
}
if self.get(ptr.alloc_id).ok().map_or(false, |alloc| alloc.static_kind != StaticKind::NotStatic) {
return Err(EvalError::ReallocatedStaticMemory);
if let Ok(alloc) = self.get(ptr.alloc_id) {
if alloc.kind != kind {
return Err(EvalError::ReallocatedWrongMemoryKind(alloc.kind, kind));
}
}
// For simplicities' sake, we implement reallocate as "alloc, copy, dealloc"
let new_ptr = self.allocate(new_size, new_align)?;
let new_ptr = self.allocate(new_size, new_align, kind)?;
self.copy(ptr.into(), new_ptr.into(), min(old_size, new_size), min(old_align, new_align), /*nonoverlapping*/true)?;
self.deallocate(ptr, Some((old_size, old_align)))?;
self.deallocate(ptr, Some((old_size, old_align)), kind)?;
Ok(new_ptr)
}
// TODO(solson): See comment on `reallocate`.
pub fn deallocate(&mut self, ptr: MemoryPointer, size_and_align: Option<(u64, u64)>) -> EvalResult<'tcx> {
pub fn deallocate(&mut self, ptr: MemoryPointer, size_and_align: Option<(u64, u64)>, kind: Kind) -> EvalResult<'tcx> {
if ptr.offset != 0 || self.get(ptr.alloc_id).is_err() {
// TODO(solson): Report error about non-__rust_allocate'd pointer.
return Err(EvalError::DeallocateNonBasePtr);
}
{
// deallocate_local in eval_context.rs relies on nothing actually having changed when this error occurs.
// So we do this test in advance.
let alloc = self.get(ptr.alloc_id)?;
if alloc.static_kind != StaticKind::NotStatic {
return Err(EvalError::DeallocatedStaticMemory);
}
if let Some((size, align)) = size_and_align {
if size != alloc.bytes.len() as u64 || align != alloc.align {
return Err(EvalError::IncorrectAllocationInformation);
}
let alloc = match self.alloc_map.remove(&ptr.alloc_id) {
Some(alloc) => alloc,
None => return Err(EvalError::DoubleFree),
};
if alloc.kind != kind {
return Err(EvalError::DeallocatedWrongMemoryKind(alloc.kind, kind));
}
if let Some((size, align)) = size_and_align {
if size != alloc.bytes.len() as u64 || align != alloc.align {
return Err(EvalError::IncorrectAllocationInformation);
}
}
let alloc = self.alloc_map.remove(&ptr.alloc_id).expect("already verified");
self.memory_usage -= alloc.bytes.len() as u64;
debug!("deallocated : {}", ptr.alloc_id);
......@@ -401,10 +410,10 @@ pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation> {
match self.alloc_map.get_mut(&id) {
Some(alloc) => match alloc.static_kind {
StaticKind::Mutable |
StaticKind::NotStatic => Ok(alloc),
StaticKind::Immutable => Err(EvalError::ModifiedConstantMemory),
Some(alloc) => if alloc.mutable == Mutability::Mutable {
Ok(alloc)
} else {
Err(EvalError::ModifiedConstantMemory)
},
None => match self.functions.get(&id) {
Some(_) => Err(EvalError::DerefFunctionPointer),
......@@ -473,10 +482,14 @@ pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
}
}
let immutable = match alloc.static_kind {
StaticKind::Mutable => " (static mut)",
StaticKind::Immutable => " (immutable)",
StaticKind::NotStatic => "",
let immutable = match (alloc.kind, alloc.mutable) {
(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)",
(Kind::Stack, _) => " (stack)",
};
trace!("{}({} bytes, alignment {}){}", msg, alloc.bytes.len(), alloc.align, immutable);
......@@ -503,7 +516,7 @@ pub fn leak_report(&self) -> usize {
let leaks: Vec<_> = self.alloc_map
.iter()
.filter_map(|(&key, val)| {
if val.static_kind == StaticKind::NotStatic {
if val.kind != Kind::Static {
Some(key)
} else {
None
......@@ -578,26 +591,40 @@ pub fn mark_static(&mut self, alloc_id: AllocId) {
}
/// mark an allocation pointed to by a static as static and initialized
pub fn mark_inner_allocation(&mut self, alloc: AllocId, mutable: 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, mutable)?;
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, mutable: bool) -> EvalResult<'tcx> {
trace!("mark_static_initialized {:?}, mutable: {:?}", alloc_id, mutable);
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 { ref mut relocations, static_kind: ref mut kind @ StaticKind::NotStatic, .. }) => {
*kind = if mutable {
StaticKind::Mutable
} else {
StaticKind::Immutable
};
Some(&mut Allocation { ref mut relocations, ref mut kind, ref mut mutable, .. }) => {
match *kind {
// const eval results can refer to "locals".
// E.g. `const Foo: &u32 = &1;` refers to the temp local that stores the `1`
Kind::Stack |
// The entire point of this function
Kind::UninitializedStatic |
// In the future const eval will allow heap allocations so we'll need to protect them
// from deallocation, too
Kind::Rust |
Kind::C => {},
Kind::Static => {
trace!("mark_static_initalized: skipping already initialized static referred to by static currently being initialized");
return Ok(());
},
// FIXME: This could be allowed, but not for env vars set during miri execution
Kind::Env => return Err(EvalError::Unimplemented("statics can't refer to env vars".to_owned())),
}
*kind = Kind::Static;
*mutable = mutability;
// take out the relocations vector to free the borrow on self, so we can call
// mark recursively
mem::replace(relocations, Default::default())
......@@ -607,7 +634,7 @@ pub fn mark_static_initalized(&mut self, alloc_id: AllocId, mutable: bool) -> Ev
};
// recurse into inner allocations
for &alloc in relocations.values() {
self.mark_inner_allocation(alloc, mutable)?;
self.mark_inner_allocation(alloc, mutability)?;
}
// put back the relocations
self.alloc_map.get_mut(&alloc_id).expect("checked above").relocations = relocations;
......
......@@ -15,6 +15,7 @@
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 @@ fn global_item(
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 @@ fn global_item(
}
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 @@ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Loca
// 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 @@ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Loca
constant.span,
mir,
Lvalue::Global(cid),
StackPopCleanup::MarkStatic(false),
StackPopCleanup::MarkStatic(Mutability::Immutable),
)
});
}
......@@ -254,7 +259,7 @@ fn visit_lvalue(
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 @@ fn visit_lvalue(
} 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);
}
......
......@@ -9,7 +9,7 @@
use error::{EvalError, EvalResult};
use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited};
use lvalue::Lvalue;
use memory::{MemoryPointer, TlsKey};
use memory::{MemoryPointer, TlsKey, Kind};
use value::{PrimVal, Value};
use rustc_data_structures::indexed_vec::Idx;
......@@ -558,7 +558,7 @@ fn call_missing_fn(
if !align.is_power_of_two() {
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
}
let ptr = self.memory.allocate(size, align)?;
let ptr = self.memory.allocate(size, align, Kind::Rust)?;
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
}
"alloc::heap::::__rust_alloc_zeroed" => {
......@@ -570,7 +570,7 @@ fn call_missing_fn(
if !align.is_power_of_two() {
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
}
let ptr = self.memory.allocate(size, align)?;
let ptr = self.memory.allocate(size, align, Kind::Rust)?;
self.memory.write_repeat(ptr.into(), 0, size)?;
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
}
......@@ -584,7 +584,7 @@ fn call_missing_fn(
if !align.is_power_of_two() {
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
}
self.memory.deallocate(ptr, Some((old_size, align)))?;
self.memory.deallocate(ptr, Some((old_size, align)), Kind::Rust)?;
}
"alloc::heap::::__rust_realloc" => {
let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
......@@ -601,7 +601,7 @@ fn call_missing_fn(
if !new_align.is_power_of_two() {
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(new_align));
}
let new_ptr = self.memory.reallocate(ptr, old_size, old_align, new_size, new_align)?;
let new_ptr = self.memory.reallocate(ptr, old_size, old_align, new_size, new_align, Kind::Rust)?;
self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
}
......@@ -657,7 +657,7 @@ fn call_c_abi(
self.write_null(dest, dest_ty)?;
} else {
let align = self.memory.pointer_size();
let ptr = self.memory.allocate(size, align)?;
let ptr = self.memory.allocate(size, align, Kind::C)?;
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
}
}
......@@ -665,7 +665,7 @@ fn call_c_abi(
"free" => {
let ptr = args[0].into_ptr(&mut self.memory)?;
if !ptr.is_null()? {
self.memory.deallocate(ptr.to_ptr()?, None)?;
self.memory.deallocate(ptr.to_ptr()?, None, Kind::C)?;
}
}
......@@ -789,7 +789,7 @@ fn call_c_abi(
}
if let Some(old) = success {
if let Some(var) = old {
self.memory.deallocate(var, None)?;
self.memory.deallocate(var, None, Kind::Env)?;
}
self.write_null(dest, dest_ty)?;
} else {
......@@ -812,11 +812,11 @@ fn call_c_abi(
}
if let Some((name, value)) = new {
// +1 for the null terminator
let value_copy = self.memory.allocate((value.len() + 1) as u64, 1)?;
let value_copy = self.memory.allocate((value.len() + 1) as u64, 1, Kind::Env)?;
self.memory.write_bytes(PrimVal::Ptr(value_copy), &value)?;
self.memory.write_bytes(PrimVal::Ptr(value_copy.offset(value.len() as u64, self.memory.layout)?), &[0])?;
if let Some(var) = self.env_vars.insert(name.to_owned(), value_copy) {
self.memory.deallocate(var, None)?;
self.memory.deallocate(var, None, Kind::Env)?;
}
self.write_null(dest, dest_ty)?;
} else {
......
use rustc::traits::{self, Reveal};
use eval_context::EvalContext;
use memory::MemoryPointer;
use memory::{MemoryPointer, Kind};
use value::{Value, PrimVal};
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};
......@@ -51,7 +51,7 @@ pub fn get_vtable(&mut self, ty: Ty<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) ->
let ptr_size = self.memory.pointer_size();
let methods = ::rustc::traits::get_vtable_methods(self.tcx, trait_ref);
let vtable = self.memory.allocate(ptr_size * (3 + methods.count() as u64), ptr_size)?;
let vtable = self.memory.allocate(ptr_size * (3 + methods.count() as u64), ptr_size, Kind::UninitializedStatic)?;
let drop = ::eval_context::resolve_drop_in_place(self.tcx, ty);
let drop = self.memory.create_fn_alloc(drop);
......@@ -68,7 +68,7 @@ pub fn get_vtable(&mut self, ty: Ty<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) ->
}
}
self.memory.mark_static_initalized(vtable.alloc_id, false)?;
self.memory.mark_static_initalized(vtable.alloc_id, Mutability::Mutable)?;
Ok(vtable)
}
......
// error-pattern: tried to deallocate Stack memory but gave Rust as the kind
fn main() {
let x = 42;
let bad_box = unsafe { std::mem::transmute::<&i32, Box<i32>>(&x) };
drop(bad_box);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册