Ensure that it is not possible to explicitly free stack memory
This commit is contained in:
parent
56d4de303f
commit
192da8819f
7 changed files with 122 additions and 90 deletions
21
src/error.rs
21
src/error.rs
|
|
@ -2,7 +2,7 @@ use std::error::Error;
|
|||
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 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||
"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 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||
"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 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
|
|||
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) =>
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
) -> 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> {
|
||||
|
|
@ -354,16 +354,16 @@ 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)?;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -414,11 +414,10 @@ impl<'a, 'tcx> EvalContext<'a, '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 {
|
||||
::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 +692,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
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)?;
|
||||
}
|
||||
}
|
||||
|
|
@ -1032,7 +1033,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 {
|
||||
|
|
@ -1686,7 +1687,7 @@ pub fn eval_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 +1729,7 @@ pub fn eval_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(());
|
||||
}
|
||||
|
|
|
|||
121
src/memory.rs
121
src/memory.rs
|
|
@ -35,19 +35,25 @@ pub struct Allocation {
|
|||
/// The alignment of the allocation to detect unaligned reads.
|
||||
pub align: u64,
|
||||
/// Whether the allocation may be modified.
|
||||
pub mutable: bool,
|
||||
/// 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 via `rust_deallocate`
|
||||
Stack,
|
||||
/// May never be deallocated
|
||||
Static,
|
||||
/// Part of env var emulation
|
||||
Env,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
|
|
@ -181,14 +187,14 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
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::Static)?;
|
||||
self.write_bytes(PrimVal::Ptr(ptr), bytes)?;
|
||||
self.mark_static_initalized(ptr.alloc_id, false)?;
|
||||
self.mark_static_initalized(ptr.alloc_id, true)?;
|
||||
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 +212,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
relocations: BTreeMap::new(),
|
||||
undef_mask: UndefMask::new(size),
|
||||
align,
|
||||
static_kind: StaticKind::NotStatic,
|
||||
kind,
|
||||
mutable: true,
|
||||
};
|
||||
let id = self.next_id;
|
||||
self.next_id.0 += 1;
|
||||
|
|
@ -214,49 +221,45 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
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 +404,10 @@ 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) => match alloc.static_kind {
|
||||
StaticKind::Mutable |
|
||||
StaticKind::NotStatic => Ok(alloc),
|
||||
StaticKind::Immutable => Err(EvalError::ModifiedConstantMemory),
|
||||
Some(alloc) => if alloc.mutable {
|
||||
Ok(alloc)
|
||||
} else {
|
||||
Err(EvalError::ModifiedConstantMemory)
|
||||
},
|
||||
None => match self.functions.get(&id) {
|
||||
Some(_) => Err(EvalError::DerefFunctionPointer),
|
||||
|
|
@ -473,10 +476,13 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let immutable = match alloc.static_kind {
|
||||
StaticKind::Mutable => " (static mut)",
|
||||
StaticKind::Immutable => " (immutable)",
|
||||
StaticKind::NotStatic => "",
|
||||
let immutable = match (alloc.kind, alloc.mutable) {
|
||||
(Kind::Static, true) => " (static mut)",
|
||||
(Kind::Static, false) => " (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 +509,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
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 +584,31 @@ 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, mutable: bool) -> EvalResult<'tcx> {
|
||||
pub fn mark_inner_allocation(&mut self, alloc: AllocId, make_immutable: bool) -> 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, make_immutable)?;
|
||||
}
|
||||
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, make_immutable: bool) -> EvalResult<'tcx> {
|
||||
trace!("mark_static_initalized {:?}, make_immutable: {:?}", alloc_id, make_immutable);
|
||||
// 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 { 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, .. }) => {
|
||||
*kind = Kind::Static;
|
||||
if make_immutable {
|
||||
*mutable = false;
|
||||
}
|
||||
// take out the relocations vector to free the borrow on self, so we can call
|
||||
// mark recursively
|
||||
mem::replace(relocations, Default::default())
|
||||
|
|
@ -607,7 +618,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
};
|
||||
// recurse into inner allocations
|
||||
for &alloc in relocations.values() {
|
||||
self.mark_inner_allocation(alloc, mutable)?;
|
||||
self.mark_inner_allocation(alloc, make_immutable)?;
|
||||
}
|
||||
// put back the relocations
|
||||
self.alloc_map.get_mut(&alloc_id).expect("checked above").relocations = relocations;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use syntax::abi::Abi;
|
|||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
"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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
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;
|
||||
|
|
@ -51,7 +51,7 @@ impl<'a, 'tcx> EvalContext<'a, '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::Static)?;
|
||||
|
||||
let drop = ::eval_context::resolve_drop_in_place(self.tcx, ty);
|
||||
let drop = self.memory.create_fn_alloc(drop);
|
||||
|
|
@ -68,7 +68,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.memory.mark_static_initalized(vtable.alloc_id, false)?;
|
||||
self.memory.mark_static_initalized(vtable.alloc_id, true)?;
|
||||
|
||||
Ok(vtable)
|
||||
}
|
||||
|
|
|
|||
8
tests/compile-fail/double_free.rs
Normal file
8
tests/compile-fail/double_free.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fn main() {
|
||||
let x = Box::new(42);
|
||||
{
|
||||
let bad_box: Box<i32> = unsafe { std::ptr::read(&x) };
|
||||
drop(bad_box);
|
||||
}
|
||||
drop(x); //~ ERROR dangling pointer was dereferenced
|
||||
}
|
||||
5
tests/compile-fail/stack_free.rs
Normal file
5
tests/compile-fail/stack_free.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
let x = 42;
|
||||
let bad_box = unsafe { std::mem::transmute::<&i32, Box<i32>>(&x) };
|
||||
drop(bad_box); //~ ERROR tried to deallocate Stack memory but gave Rust as the kind
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue