Skip to content

Commit 5328c5d

Browse files
authored
Merge pull request rust-lang#245 from oli-obk/funky_allocs
Ensure that it is not possible to explicitly free stack memory
2 parents a29ba6a + 45ab975 commit 5328c5d

File tree

9 files changed

+165
-109
lines changed

9 files changed

+165
-109
lines changed

src/const_eval.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc::traits::Reveal;
22
use rustc::ty::{self, TyCtxt, Ty, Instance};
3+
use syntax::ast::Mutability;
34

45
use error::{EvalError, EvalResult};
56
use lvalue::{Global, GlobalId, Lvalue};
@@ -25,7 +26,12 @@ pub fn eval_body_as_primval<'a, 'tcx>(
2526
ecx.tcx,
2627
ty::ParamEnv::empty(Reveal::All),
2728
mir.span);
28-
let cleanup = StackPopCleanup::MarkStatic(mutable);
29+
let mutability = if mutable {
30+
Mutability::Mutable
31+
} else {
32+
Mutability::Immutable
33+
};
34+
let cleanup = StackPopCleanup::MarkStatic(mutability);
2935
let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
3036
trace!("pushing stack frame for global: {}", name);
3137
ecx.push_stack_frame(

src/error.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::error::Error;
22
use std::fmt;
33
use rustc::mir;
44
use rustc::ty::{FnSig, Ty, layout};
5-
use memory::MemoryPointer;
5+
use memory::{MemoryPointer, Kind};
66
use rustc_const_math::ConstMathErr;
77
use syntax::codemap::Span;
88

@@ -12,6 +12,7 @@ pub enum EvalError<'tcx> {
1212
NoMirFor(String),
1313
UnterminatedCString(MemoryPointer),
1414
DanglingPointerDeref,
15+
DoubleFree,
1516
InvalidMemoryAccess,
1617
InvalidFunctionPointer,
1718
InvalidBool,
@@ -56,8 +57,8 @@ pub enum EvalError<'tcx> {
5657
AssumptionNotHeld,
5758
InlineAsm,
5859
TypeNotPrimitive(Ty<'tcx>),
59-
ReallocatedStaticMemory,
60-
DeallocatedStaticMemory,
60+
ReallocatedWrongMemoryKind(Kind, Kind),
61+
DeallocatedWrongMemoryKind(Kind, Kind),
6162
ReallocateNonBasePtr,
6263
DeallocateNonBasePtr,
6364
IncorrectAllocationInformation,
@@ -84,6 +85,8 @@ impl<'tcx> Error for EvalError<'tcx> {
8485
"tried to access memory through an invalid pointer",
8586
DanglingPointerDeref =>
8687
"dangling pointer was dereferenced",
88+
DoubleFree =>
89+
"tried to deallocate dangling pointer",
8790
InvalidFunctionPointer =>
8891
"tried to use an integer pointer or a dangling pointer as a function pointer",
8992
InvalidBool =>
@@ -148,10 +151,10 @@ impl<'tcx> Error for EvalError<'tcx> {
148151
"miri does not support inline assembly",
149152
TypeNotPrimitive(_) =>
150153
"expected primitive type, got nonprimitive",
151-
ReallocatedStaticMemory =>
152-
"tried to reallocate static memory",
153-
DeallocatedStaticMemory =>
154-
"tried to deallocate static memory",
154+
ReallocatedWrongMemoryKind(_, _) =>
155+
"tried to reallocate memory from one kind to another",
156+
DeallocatedWrongMemoryKind(_, _) =>
157+
"tried to deallocate memory of the wrong kind",
155158
ReallocateNonBasePtr =>
156159
"tried to reallocate with a pointer not to the beginning of an existing object",
157160
DeallocateNonBasePtr =>
@@ -198,6 +201,10 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
198201
write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got),
199202
ArrayIndexOutOfBounds(span, len, index) =>
200203
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
204+
ReallocatedWrongMemoryKind(old, new) =>
205+
write!(f, "tried to reallocate memory from {:?} to {:?}", old, new),
206+
DeallocatedWrongMemoryKind(old, new) =>
207+
write!(f, "tried to deallocate {:?} memory but gave {:?} as the kind", old, new),
201208
Math(span, ref err) =>
202209
write!(f, "{:?} at {:?}", err, span),
203210
Intrinsic(ref err) =>

src/eval_context.rs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder};
1212
use rustc::traits;
1313
use rustc_data_structures::indexed_vec::Idx;
1414
use syntax::codemap::{self, DUMMY_SP, Span};
15-
use syntax::ast;
15+
use syntax::ast::{self, Mutability};
1616
use syntax::abi::Abi;
1717

1818
use error::{EvalError, EvalResult};
@@ -98,8 +98,7 @@ pub enum StackPopCleanup {
9898
/// isn't modifyable afterwards in case of constants.
9999
/// In case of `static mut`, mark the memory to ensure it's never marked as immutable through
100100
/// references or deallocated
101-
/// The bool decides whether the value is mutable (true) or not (false)
102-
MarkStatic(bool),
101+
MarkStatic(Mutability),
103102
/// A regular stackframe added due to a function call will need to get forwarded to the next
104103
/// block
105104
Goto(mir::BasicBlock),
@@ -154,7 +153,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
154153
) -> EvalResult<'tcx, MemoryPointer> {
155154
let size = self.type_size_with_substs(ty, substs)?.expect("cannot alloc memory for unsized type");
156155
let align = self.type_align_with_substs(ty, substs)?;
157-
self.memory.allocate(size, align)
156+
self.memory.allocate(size, align, ::memory::Kind::Stack)
158157
}
159158

160159
pub fn memory(&self) -> &Memory<'a, 'tcx> {
@@ -370,7 +369,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
370369
// see comment on `initialized` field
371370
assert!(!global_value.initialized);
372371
global_value.initialized = true;
373-
assert!(global_value.mutable);
372+
assert_eq!(global_value.mutable, Mutability::Mutable);
374373
global_value.mutable = mutable;
375374
} else {
376375
bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue);
@@ -414,11 +413,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
414413
trace!("deallocating local");
415414
let ptr = ptr.to_ptr()?;
416415
self.memory.dump_alloc(ptr.alloc_id);
417-
match self.memory.deallocate(ptr, None) {
418-
// We could alternatively check whether the alloc_id is static before calling
419-
// deallocate, but this is much simpler and is probably the rare case.
420-
Ok(()) | Err(EvalError::DeallocatedStaticMemory) => {},
421-
other => return other,
416+
match self.memory.get(ptr.alloc_id)?.kind {
417+
// for a constant like `const FOO: &i32 = &1;` the local containing
418+
// the `1` is referred to by the global. We transitively marked everything
419+
// the global refers to as static itself, so we don't free it here
420+
::memory::Kind::Static => {}
421+
::memory::Kind::Stack => self.memory.deallocate(ptr, None, ::memory::Kind::Stack)?,
422+
other => bug!("local contained non-stack memory: {:?}", other),
422423
}
423424
};
424425
Ok(())
@@ -693,11 +694,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
693694
return Err(EvalError::NeedsRfc("\"heap\" allocations".to_string()));
694695
}
695696
// FIXME: call the `exchange_malloc` lang item if available
696-
if self.type_size(ty)?.expect("box only works with sized types") == 0 {
697+
let size = self.type_size(ty)?.expect("box only works with sized types");
698+
if size == 0 {
697699
let align = self.type_align(ty)?;
698700
self.write_primval(dest, PrimVal::Bytes(align.into()), dest_ty)?;
699701
} else {
700-
let ptr = self.alloc_ptr(ty)?;
702+
let align = self.type_align(ty)?;
703+
let ptr = self.memory.allocate(size, align, ::memory::Kind::Rust)?;
701704
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
702705
}
703706
}
@@ -1022,7 +1025,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10221025
}
10231026
Lvalue::Ptr { .. } => lvalue,
10241027
Lvalue::Global(cid) => {
1025-
let global_val = *self.globals.get(&cid).expect("global not cached");
1028+
let global_val = self.globals.get(&cid).expect("global not cached").clone();
10261029
match global_val.value {
10271030
Value::ByRef(ptr, aligned) =>
10281031
Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None },
@@ -1108,8 +1111,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11081111

11091112
match dest {
11101113
Lvalue::Global(cid) => {
1111-
let dest = *self.globals.get_mut(&cid).expect("global should be cached");
1112-
if !dest.mutable {
1114+
let dest = self.globals.get_mut(&cid).expect("global should be cached").clone();
1115+
if dest.mutable == Mutability::Immutable {
11131116
return Err(EvalError::ModifiedConstantMemory);
11141117
}
11151118
let write_dest = |this: &mut Self, val| {
@@ -1594,8 +1597,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
15941597
pub fn modify_global<F>(&mut self, cid: GlobalId<'tcx>, f: F) -> EvalResult<'tcx>
15951598
where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
15961599
{
1597-
let mut val = *self.globals.get(&cid).expect("global not cached");
1598-
if !val.mutable {
1600+
let mut val = self.globals.get(&cid).expect("global not cached").clone();
1601+
if val.mutable == Mutability::Immutable {
15991602
return Err(EvalError::ModifiedConstantMemory);
16001603
}
16011604
val.value = f(self, val.value)?;
@@ -1686,7 +1689,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
16861689
}
16871690

16881691
// Return value
1689-
let ret_ptr = ecx.memory.allocate(ecx.tcx.data_layout.pointer_size.bytes(), ecx.tcx.data_layout.pointer_align.abi())?;
1692+
let ret_ptr = ecx.memory.allocate(ecx.tcx.data_layout.pointer_size.bytes(), ecx.tcx.data_layout.pointer_align.abi(), ::memory::Kind::Stack)?;
16901693
cleanup_ptr = Some(ret_ptr);
16911694

16921695
// Push our stack frame
@@ -1728,7 +1731,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
17281731

17291732
while ecx.step()? {}
17301733
if let Some(cleanup_ptr) = cleanup_ptr {
1731-
ecx.memory.deallocate(cleanup_ptr, None)?;
1734+
ecx.memory.deallocate(cleanup_ptr, None, ::memory::Kind::Stack)?;
17321735
}
17331736
return Ok(());
17341737
}

src/lvalue.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use rustc::mir;
22
use rustc::ty::layout::{Size, Align};
33
use rustc::ty::{self, Ty};
44
use rustc_data_structures::indexed_vec::Idx;
5+
use syntax::ast::Mutability;
56

67
use error::{EvalError, EvalResult};
78
use eval_context::EvalContext;
@@ -51,15 +52,15 @@ pub struct GlobalId<'tcx> {
5152
pub(super) promoted: Option<mir::Promoted>,
5253
}
5354

54-
#[derive(Copy, Clone, Debug)]
55+
#[derive(Clone, Debug)]
5556
pub struct Global<'tcx> {
5657
pub(super) value: Value,
5758
/// Only used in `force_allocation` to ensure we don't mark the memory
5859
/// before the static is initialized. It is possible to convert a
5960
/// global which initially is `Value::ByVal(PrimVal::Undef)` and gets
6061
/// lifted to an allocation before the static is fully initialized
6162
pub(super) initialized: bool,
62-
pub(super) mutable: bool,
63+
pub(super) mutable: Mutability,
6364
pub(super) ty: Ty<'tcx>,
6465
}
6566

@@ -113,13 +114,13 @@ impl<'tcx> Global<'tcx> {
113114
pub(super) fn uninitialized(ty: Ty<'tcx>) -> Self {
114115
Global {
115116
value: Value::ByVal(PrimVal::Undef),
116-
mutable: true,
117+
mutable: Mutability::Mutable,
117118
ty,
118119
initialized: false,
119120
}
120121
}
121122

122-
pub(super) fn initialized(ty: Ty<'tcx>, value: Value, mutable: bool) -> Self {
123+
pub(super) fn initialized(ty: Ty<'tcx>, value: Value, mutable: Mutability) -> Self {
123124
Global {
124125
value,
125126
mutable,

0 commit comments

Comments
 (0)