From 082effb3ee6b36bfac00ae8ff8cf2f4e1b253b5c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 5 Jul 2016 14:27:27 +0200 Subject: [PATCH 1/8] align allocations in the worst possible way --- src/error.rs | 9 +++++ src/interpreter/mod.rs | 37 +++++++++++------ src/interpreter/terminator.rs | 7 ++-- src/memory.rs | 49 ++++++++++++++--------- tests/compile-fail/oom.rs | 2 +- tests/compile-fail/oom2.rs | 2 +- tests/compile-fail/out_of_bounds_read.rs | 2 +- tests/compile-fail/out_of_bounds_read2.rs | 2 +- 8 files changed, 71 insertions(+), 39 deletions(-) diff --git a/src/error.rs b/src/error.rs index 9952cfd9a7e8..6f033557b965 100644 --- a/src/error.rs +++ b/src/error.rs @@ -36,6 +36,10 @@ pub enum EvalError<'tcx> { }, ExecutionTimeLimitReached, StackFrameLimitReached, + AlignmentCheckFailed { + required: usize, + has: usize, + }, } pub type EvalResult<'tcx, T> = Result>; @@ -82,6 +86,8 @@ impl<'tcx> Error for EvalError<'tcx> { "reached the configured maximum execution time", EvalError::StackFrameLimitReached => "reached the configured maximum number of stack frames", + EvalError::AlignmentCheckFailed{..} => + "tried to execute a misaligned read or write", } } @@ -106,6 +112,9 @@ impl<'tcx> fmt::Display for EvalError<'tcx> { EvalError::OutOfMemory { allocation_size, memory_size, memory_usage } => write!(f, "tried to allocate {} more bytes, but only {} bytes are free of the {} byte memory", allocation_size, memory_size - memory_usage, memory_size), + EvalError::AlignmentCheckFailed { required, has } => + write!(f, "tried to access memory with alignment {}, but alignment {} is required", + has, required), _ => write!(f, "{}", self.description()), } } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 34fa9d8de6fd..8d6c526c0c20 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -153,7 +153,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match output_ty { ty::FnConverging(ty) => { let size = self.type_size_with_substs(ty, substs); - self.memory.allocate(size).map(Some) + let align = self.type_align_with_substs(ty, substs); + self.memory.allocate(size, align).map(Some) } ty::FnDiverging => Ok(None), } @@ -177,7 +178,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; macro_rules! i2p { ($i:ident, $n:expr) => {{ - let ptr = self.memory.allocate($n)?; + let ptr = self.memory.allocate($n, $n)?; self.memory.write_int(ptr, $i as i64, $n)?; Ok(ptr) }} @@ -202,8 +203,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Integral(ConstInt::Usize(ConstUsize::Us64(i))) => i2p!(i, 8), Str(ref s) => { let psize = self.memory.pointer_size(); - let static_ptr = self.memory.allocate(s.len())?; - let ptr = self.memory.allocate(psize * 2)?; + let static_ptr = self.memory.allocate(s.len(), 1)?; + let ptr = self.memory.allocate(psize * 2, psize)?; self.memory.write_bytes(static_ptr, s.as_bytes())?; self.memory.write_ptr(ptr, static_ptr)?; self.memory.write_usize(ptr.offset(psize as isize), s.len() as u64)?; @@ -211,19 +212,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } ByteStr(ref bs) => { let psize = self.memory.pointer_size(); - let static_ptr = self.memory.allocate(bs.len())?; - let ptr = self.memory.allocate(psize)?; + let static_ptr = self.memory.allocate(bs.len(), 1)?; + let ptr = self.memory.allocate(psize, psize)?; self.memory.write_bytes(static_ptr, bs)?; self.memory.write_ptr(ptr, static_ptr)?; Ok(ptr) } Bool(b) => { - let ptr = self.memory.allocate(1)?; + let ptr = self.memory.allocate(1, 1)?; self.memory.write_bool(ptr, b)?; Ok(ptr) } Char(c) => { - let ptr = self.memory.allocate(4)?; + let ptr = self.memory.allocate(4, 4)?; self.memory.write_uint(ptr, c as u64, 4)?; Ok(ptr) }, @@ -269,10 +270,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.type_size_with_substs(ty, self.substs()) } + fn type_align(&self, ty: Ty<'tcx>) -> usize { + self.type_align_with_substs(ty, self.substs()) + } + fn type_size_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize { self.type_layout_with_substs(ty, substs).size(&self.tcx.data_layout).bytes() as usize } + fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize { + self.type_layout_with_substs(ty, substs).align(&self.tcx.data_layout).pref() as usize + } + fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout { self.type_layout_with_substs(ty, self.substs()) } @@ -306,7 +315,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let locals: EvalResult<'tcx, Vec> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| { let size = self.type_size_with_substs(ty, substs); - self.memory.allocate(size) + let align = self.type_align_with_substs(ty, substs); + self.memory.allocate(size, align) }).collect(); self.stack.push(Frame { @@ -553,7 +563,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Box(ty) => { let size = self.type_size(ty); - let ptr = self.memory.allocate(size)?; + let align = self.type_align(ty); + let ptr = self.memory.allocate(size, align)?; self.memory.write_ptr(dest, ptr)?; } @@ -701,7 +712,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Item { def_id, substs } => { if let ty::TyFnDef(..) = ty.sty { // function items are zero sized - Ok(self.memory.allocate(0)?) + Ok(self.memory.allocate(0, 0)?) } else { let cid = ConstantId { def_id: def_id, @@ -955,9 +966,9 @@ pub fn eval_main<'a, 'tcx: 'a>( if mir.arg_decls.len() == 2 { // start function let ptr_size = ecx.memory().pointer_size(); - let nargs = ecx.memory_mut().allocate(ptr_size).expect("can't allocate memory for nargs"); + let nargs = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for nargs"); ecx.memory_mut().write_usize(nargs, 0).unwrap(); - let args = ecx.memory_mut().allocate(ptr_size).expect("can't allocate memory for arg pointer"); + let args = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for arg pointer"); ecx.memory_mut().write_usize(args, 0).unwrap(); ecx.frame_mut().locals[0] = nargs; ecx.frame_mut().locals[1] = args; diff --git a/src/interpreter/terminator.rs b/src/interpreter/terminator.rs index 2fbc9a63ef68..28b130e3d572 100644 --- a/src/interpreter/terminator.rs +++ b/src/interpreter/terminator.rs @@ -88,7 +88,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match func_ty.sty { ty::TyFnPtr(bare_fn_ty) => { let ptr = self.eval_operand(func)?; - assert_eq!(ptr.offset, 0); let fn_ptr = self.memory.read_ptr(ptr)?; let FunctionDefinition { def_id, substs, fn_ty } = self.memory.get_fn(fn_ptr.alloc_id)?; if fn_ty != bare_fn_ty { @@ -416,14 +415,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match &link_name[..] { "__rust_allocate" => { let size = self.memory.read_usize(args[0])?; - let ptr = self.memory.allocate(size as usize)?; + let align = self.memory.read_usize(args[1])?; + let ptr = self.memory.allocate(size as usize, align as usize)?; self.memory.write_ptr(dest, ptr)?; } "__rust_reallocate" => { let ptr = self.memory.read_ptr(args[0])?; let size = self.memory.read_usize(args[2])?; - let new_ptr = self.memory.reallocate(ptr, size as usize)?; + let align = self.memory.read_usize(args[3])?; + let new_ptr = self.memory.reallocate(ptr, size as usize, align as usize)?; self.memory.write_ptr(dest, new_ptr)?; } diff --git a/src/memory.rs b/src/memory.rs index 2453b1f6e67a..ca041dc1d953 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -29,6 +29,7 @@ pub struct Allocation { pub bytes: Vec, pub relocations: BTreeMap, pub undef_mask: UndefMask, + pub align: usize, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -98,10 +99,11 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { bytes: Vec::new(), relocations: BTreeMap::new(), undef_mask: UndefMask::new(0), + align: 0, }; mem.alloc_map.insert(ZST_ALLOC_ID, alloc); // check that additional zst allocs work - debug_assert!(mem.allocate(0).unwrap().points_to_zst()); + debug_assert!(mem.allocate(0, 0).unwrap().points_to_zst()); debug_assert!(mem.get(ZST_ALLOC_ID).is_ok()); mem } @@ -133,62 +135,71 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } } - pub fn allocate(&mut self, size: usize) -> EvalResult<'tcx, Pointer> { + pub fn allocate(&mut self, size: usize, align: usize) -> EvalResult<'tcx, Pointer> { if size == 0 { return Ok(Pointer::zst_ptr()); } + // make sure we can offset the result pointer by the worst possible alignment + // this allows cheaply checking for alignment directly in the pointer + let least_aligned_size = size + align; if self.memory_size - self.memory_usage < size as u64 { return Err(EvalError::OutOfMemory { - allocation_size: size as u64, + allocation_size: least_aligned_size as u64, memory_size: self.memory_size, memory_usage: self.memory_usage, }); } self.memory_usage += size as u64; let alloc = Allocation { - bytes: vec![0; size], + bytes: vec![0; least_aligned_size], relocations: BTreeMap::new(), - undef_mask: UndefMask::new(size), + undef_mask: UndefMask::new(least_aligned_size), + align: align, }; let id = self.next_id; self.next_id.0 += 1; self.alloc_map.insert(id, alloc); Ok(Pointer { alloc_id: id, - offset: 0, + // offset by the alignment, so larger accesses will fail + offset: align, }) } // 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: Pointer, new_size: usize) -> EvalResult<'tcx, Pointer> { - if ptr.offset != 0 { + pub fn reallocate(&mut self, ptr: Pointer, new_size: usize, align: usize) -> EvalResult<'tcx, Pointer> { + if ptr.offset != self.get(ptr.alloc_id)?.align { // TODO(solson): Report error about non-__rust_allocate'd pointer. return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); } if ptr.points_to_zst() { - return self.allocate(new_size); + return self.allocate(new_size, align); } - let size = self.get_mut(ptr.alloc_id)?.bytes.len(); + let size = self.get(ptr.alloc_id)?.bytes.len(); + let least_aligned_size = new_size + align; - if new_size > size { - let amount = new_size - size; + if least_aligned_size > size { + let amount = least_aligned_size - size; self.memory_usage += amount as u64; let alloc = self.get_mut(ptr.alloc_id)?; alloc.bytes.extend(iter::repeat(0).take(amount)); alloc.undef_mask.grow(amount, false); - } else if size > new_size { + } else if size > least_aligned_size { // it's possible to cause miri to use arbitrary amounts of memory that aren't detectable // through the memory_usage value, by allocating a lot and reallocating to zero - self.memory_usage -= (size - new_size) as u64; - self.clear_relocations(ptr.offset(new_size as isize), size - new_size)?; + self.memory_usage -= (size - least_aligned_size) as u64; + self.clear_relocations(ptr.offset(least_aligned_size as isize), size - least_aligned_size)?; let alloc = self.get_mut(ptr.alloc_id)?; - alloc.bytes.truncate(new_size); - alloc.undef_mask.truncate(new_size); + alloc.bytes.truncate(least_aligned_size); + alloc.undef_mask.truncate(least_aligned_size); } - Ok(ptr) + Ok(Pointer { + alloc_id: ptr.alloc_id, + offset: align, + }) } // TODO(solson): See comment on `reallocate`. @@ -196,7 +207,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { if ptr.points_to_zst() { return Ok(()); } - if ptr.offset != 0 { + if ptr.offset != self.get(ptr.alloc_id)?.align { // TODO(solson): Report error about non-__rust_allocate'd pointer. return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); } diff --git a/tests/compile-fail/oom.rs b/tests/compile-fail/oom.rs index 83109a77e620..d5f021bda704 100644 --- a/tests/compile-fail/oom.rs +++ b/tests/compile-fail/oom.rs @@ -6,6 +6,6 @@ fn bar() { assert_eq!(x, 6); } -fn main() { //~ ERROR tried to allocate 4 more bytes, but only 0 bytes are free of the 0 byte memory +fn main() { //~ ERROR tried to allocate 8 more bytes, but only 0 bytes are free of the 0 byte memory bar(); } diff --git a/tests/compile-fail/oom2.rs b/tests/compile-fail/oom2.rs index 63c51dbaa7d2..65ef0dd0b7da 100644 --- a/tests/compile-fail/oom2.rs +++ b/tests/compile-fail/oom2.rs @@ -3,7 +3,7 @@ fn bar(i: i32) { if i < 1000 { - bar(i + 1) //~ ERROR tried to allocate 4 more bytes, but only 1 bytes are free of the 1000 byte memory + bar(i + 1) //~ ERROR tried to allocate 8 more bytes, but only 1 bytes are free of the 1000 byte memory //~^NOTE inside call to bar //~|NOTE inside call to bar //~|NOTE inside call to bar diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read.rs index f6a305840c24..29355992e44c 100644 --- a/tests/compile-fail/out_of_bounds_read.rs +++ b/tests/compile-fail/out_of_bounds_read.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.get_unchecked(5) }; //~ ERROR: which has size 2 + let x = unsafe { *v.get_unchecked(5) }; //~ ERROR: which has size 3 panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index 5509a8346e55..388ed8b13063 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.get_unchecked(5) }; //~ ERROR: memory access of 5..6 outside bounds of allocation + let x = unsafe { *v.get_unchecked(5) }; //~ ERROR: memory access of 6..7 outside bounds of allocation panic!("this should never print: {}", x); } From 7161c72320816948733a85b1759b46a1cf2d9d92 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 6 Jul 2016 10:58:26 +0200 Subject: [PATCH 2/8] abi alignment is the correct one --- src/interpreter/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 8d6c526c0c20..3454fdc7dbc4 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -279,7 +279,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize { - self.type_layout_with_substs(ty, substs).align(&self.tcx.data_layout).pref() as usize + self.type_layout_with_substs(ty, substs).align(&self.tcx.data_layout).abi() as usize } fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout { From 50987e3697d58a1d1e48a778d1e5875d6adea657 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 6 Jul 2016 10:58:51 +0200 Subject: [PATCH 3/8] some methods to check pointers for correct alignment --- src/memory.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/memory.rs b/src/memory.rs index ca041dc1d953..4afcf05d67ad 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -51,6 +51,25 @@ impl Pointer { offset: 0, } } + pub fn is_aligned_to(&self, align: usize) -> bool { + self.offset % align == 0 + } + pub fn check_align(&self, align: usize) -> EvalResult<'static, ()> { + if self.is_aligned_to(align) { + Ok(()) + } else { + let mut best = self.offset; + let mut i = 1; + while best > 0 && (best & 1 == 0) { + best >>= 1; + i <<= 1; + } + Err(EvalError::AlignmentCheckFailed { + required: align, + has: i, + }) + } + } } #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] From 1bd8e04228d807c6ea0b7813c6c8689527f65252 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 6 Jul 2016 11:12:44 +0200 Subject: [PATCH 4/8] check alignment in various places --- src/interpreter/mod.rs | 10 ++++++++-- src/interpreter/terminator.rs | 8 ++++++-- src/memory.rs | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 3454fdc7dbc4..c5ebd96cda6b 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -520,12 +520,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } Repeat(ref operand, _) => { - let (elem_size, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (self.type_size(elem_ty), n), + let (elem_size, elem_align, length) = match dest_ty.sty { + ty::TyArray(elem_ty, n) => (self.type_size(elem_ty), self.type_align(elem_ty), n), _ => panic!("tried to assign array-repeat to non-array type {:?}", dest_ty), }; let src = self.eval_operand(operand)?; + src.check_align(elem_align)?; + dest.check_align(elem_align)?; for i in 0..length { let elem_dest = dest.offset((i * elem_size) as isize); self.memory.copy(src, elem_dest, elem_size)?; @@ -592,6 +594,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let src = self.eval_operand(operand)?; let src_ty = self.operand_ty(operand); // FIXME(solson): Wrong for almost everything. + // FIXME: check alignment warn!("misc cast from {:?} to {:?}", src_ty, dest_ty); let dest_size = self.type_size(dest_ty); let src_size = self.type_size(src_ty); @@ -845,6 +848,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> { let size = self.type_size(ty); + let align = self.type_align(ty); + src.check_align(align)?; + dest.check_align(align)?; self.memory.copy(src, dest, size)?; Ok(()) } diff --git a/src/interpreter/terminator.rs b/src/interpreter/terminator.rs index 28b130e3d572..d5b7dbaf6238 100644 --- a/src/interpreter/terminator.rs +++ b/src/interpreter/terminator.rs @@ -289,8 +289,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "copy_nonoverlapping" => { let elem_ty = *substs.types.get(subst::FnSpace, 0); let elem_size = self.type_size(elem_ty); + let elem_align = self.type_align(elem_ty); let src = self.memory.read_ptr(args_ptrs[0])?; + src.check_align(elem_align)?; let dest = self.memory.read_ptr(args_ptrs[1])?; + dest.check_align(elem_align)?; let count = self.memory.read_isize(args_ptrs[2])?; self.memory.copy(src, dest, count as usize * elem_size)?; } @@ -307,8 +310,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "init" => self.memory.write_repeat(dest, 0, dest_layout.size(&self.tcx.data_layout).bytes() as usize)?, "min_align_of" => { - // FIXME: use correct value - self.memory.write_int(dest, 1, pointer_size)?; + let elem_ty = *substs.types.get(subst::FnSpace, 0); + let elem_align = self.type_align(elem_ty); + self.memory.write_uint(dest, elem_align as u64, pointer_size)?; } "move_val_init" => { diff --git a/src/memory.rs b/src/memory.rs index 4afcf05d67ad..cac4a8bb7c19 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -463,6 +463,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } pub fn read_bool(&self, ptr: Pointer) -> EvalResult<'tcx, bool> { + ptr.check_align(self.layout.i1_align.abi() as usize)?; let bytes = self.get_bytes(ptr, 1)?; match bytes[0] { 0 => Ok(false), @@ -472,14 +473,27 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } pub fn write_bool(&mut self, ptr: Pointer, b: bool) -> EvalResult<'tcx, ()> { + ptr.check_align(self.layout.i1_align.abi() as usize)?; self.get_bytes_mut(ptr, 1).map(|bytes| bytes[0] = b as u8) } + fn check_int_align(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, ()> { + match size { + 1 => ptr.check_align(self.layout.i8_align.abi() as usize), + 2 => ptr.check_align(self.layout.i16_align.abi() as usize), + 4 => ptr.check_align(self.layout.i32_align.abi() as usize), + 8 => ptr.check_align(self.layout.i64_align.abi() as usize), + _ => panic!("bad integer size"), + } + } + pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, i64> { + self.check_int_align(ptr, size)?; self.get_bytes(ptr, size).map(|b| read_target_int(self.endianess(), b).unwrap()) } pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<'tcx, ()> { + self.check_int_align(ptr, size)?; let endianess = self.endianess(); let b = self.get_bytes_mut(ptr, size)?; write_target_int(endianess, b, n).unwrap(); @@ -487,10 +501,12 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, u64> { + self.check_int_align(ptr, size)?; self.get_bytes(ptr, size).map(|b| read_target_uint(self.endianess(), b).unwrap()) } pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<'tcx, ()> { + self.check_int_align(ptr, size)?; let endianess = self.endianess(); let b = self.get_bytes_mut(ptr, size)?; write_target_uint(endianess, b, n).unwrap(); From aca691160dbeae0c18049d1c23091e644261b528 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 6 Jul 2016 11:19:24 +0200 Subject: [PATCH 5/8] add a test --- tests/compile-fail/alignment.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/compile-fail/alignment.rs diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/alignment.rs new file mode 100644 index 000000000000..4faaa359df62 --- /dev/null +++ b/tests/compile-fail/alignment.rs @@ -0,0 +1,11 @@ +fn main() { + // miri always gives allocations the worst possible alignment, so a `u8` array is guaranteed + // to be at the virtual location 1 (so one byte offset from the ultimate alignemnt location 0) + let mut x = [0u8; 20]; + let x_ptr: *mut u8 = &mut x[0]; + let y_ptr = x_ptr as *mut u64; + unsafe { + *y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment + } + panic!("unreachable in miri"); +} From 613d15c672b3a857521ebd15daef384e2ae997f3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 7 Jul 2016 13:19:17 +0200 Subject: [PATCH 6/8] clippy --- src/interpreter/mod.rs | 12 ++++++------ src/memory.rs | 2 +- src/primval.rs | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 16f260852808..0506335dc221 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -198,18 +198,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Integral(ConstInt::InferSigned(_)) => unreachable!(), Integral(ConstInt::I8(i)) => i2p!(i, 1), Integral(ConstInt::U8(i)) => i2p!(i, 1), + Integral(ConstInt::Isize(ConstIsize::Is16(i))) | Integral(ConstInt::I16(i)) => i2p!(i, 2), + Integral(ConstInt::Usize(ConstUsize::Us16(i))) | Integral(ConstInt::U16(i)) => i2p!(i, 2), + Integral(ConstInt::Isize(ConstIsize::Is32(i))) | Integral(ConstInt::I32(i)) => i2p!(i, 4), + Integral(ConstInt::Usize(ConstUsize::Us32(i))) | Integral(ConstInt::U32(i)) => i2p!(i, 4), + Integral(ConstInt::Isize(ConstIsize::Is64(i))) | Integral(ConstInt::I64(i)) => i2p!(i, 8), + Integral(ConstInt::Usize(ConstUsize::Us64(i))) | Integral(ConstInt::U64(i)) => i2p!(i, 8), - Integral(ConstInt::Isize(ConstIsize::Is16(i))) => i2p!(i, 2), - Integral(ConstInt::Isize(ConstIsize::Is32(i))) => i2p!(i, 4), - Integral(ConstInt::Isize(ConstIsize::Is64(i))) => i2p!(i, 8), - Integral(ConstInt::Usize(ConstUsize::Us16(i))) => i2p!(i, 2), - Integral(ConstInt::Usize(ConstUsize::Us32(i))) => i2p!(i, 4), - Integral(ConstInt::Usize(ConstUsize::Us64(i))) => i2p!(i, 8), Str(ref s) => { let psize = self.memory.pointer_size(); let static_ptr = self.memory.allocate(s.len(), 1)?; diff --git a/src/memory.rs b/src/memory.rs index 534276b7378c..d4f8eb58f2f7 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -127,7 +127,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { mem } - pub fn allocations<'b>(&'b self) -> ::std::collections::hash_map::Iter<'b, AllocId, Allocation> { + pub fn allocations(&self) -> ::std::collections::hash_map::Iter { self.alloc_map.iter() } diff --git a/src/primval.rs b/src/primval.rs index 966196d8d1a5..1ec751681703 100644 --- a/src/primval.rs +++ b/src/primval.rs @@ -1,3 +1,6 @@ +#![allow(unknown_lints)] +#![allow(float_cmp)] + use rustc::mir::repr as mir; use error::{EvalError, EvalResult}; From ec897f9156332a1d1bb39975bfcfc32a3ea8e473 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 22 Jul 2016 16:35:39 +0200 Subject: [PATCH 7/8] don't allow runtime-aligning of memory --- src/interpreter/mod.rs | 12 +- src/interpreter/terminator.rs | 4 +- src/memory.rs | 142 +++++++++++----------- tests/compile-fail/oom.rs | 2 +- tests/compile-fail/oom2.rs | 2 +- tests/compile-fail/out_of_bounds_read.rs | 2 +- tests/compile-fail/out_of_bounds_read2.rs | 2 +- 7 files changed, 79 insertions(+), 87 deletions(-) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 0506335dc221..c1e1fff999fd 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -535,11 +535,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }; let src = self.eval_operand(operand)?; - src.check_align(elem_align)?; - dest.check_align(elem_align)?; for i in 0..length { let elem_dest = dest.offset((i * elem_size) as isize); - self.memory.copy(src, elem_dest, elem_size)?; + self.memory.copy(src, elem_dest, elem_size, elem_align)?; } } @@ -603,17 +601,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let src = self.eval_operand(operand)?; let src_ty = self.operand_ty(operand); // FIXME(solson): Wrong for almost everything. - // FIXME: check alignment warn!("misc cast from {:?} to {:?}", src_ty, dest_ty); let dest_size = self.type_size(dest_ty); let src_size = self.type_size(src_ty); + let dest_align = self.type_align(dest_ty); // Hack to support fat pointer -> thin pointer casts to keep tests for // other things passing for now. let is_fat_ptr_cast = pointee_type(src_ty).map_or(false, |ty| !self.type_is_sized(ty)); if dest_size == src_size || is_fat_ptr_cast { - self.memory.copy(src, dest, dest_size)?; + self.memory.copy(src, dest, dest_size, dest_align)?; } else { return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))); } @@ -858,9 +856,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> { let size = self.type_size(ty); let align = self.type_align(ty); - src.check_align(align)?; - dest.check_align(align)?; - self.memory.copy(src, dest, size)?; + self.memory.copy(src, dest, size, align)?; Ok(()) } diff --git a/src/interpreter/terminator.rs b/src/interpreter/terminator.rs index d5b7dbaf6238..568d8358f087 100644 --- a/src/interpreter/terminator.rs +++ b/src/interpreter/terminator.rs @@ -291,11 +291,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let elem_size = self.type_size(elem_ty); let elem_align = self.type_align(elem_ty); let src = self.memory.read_ptr(args_ptrs[0])?; - src.check_align(elem_align)?; let dest = self.memory.read_ptr(args_ptrs[1])?; - dest.check_align(elem_align)?; let count = self.memory.read_isize(args_ptrs[2])?; - self.memory.copy(src, dest, count as usize * elem_size)?; + self.memory.copy(src, dest, count as usize * elem_size, elem_align)?; } "discriminant_value" => { diff --git a/src/memory.rs b/src/memory.rs index d4f8eb58f2f7..91ae90da8b6f 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -51,25 +51,6 @@ impl Pointer { offset: 0, } } - pub fn is_aligned_to(&self, align: usize) -> bool { - self.offset % align == 0 - } - pub fn check_align(&self, align: usize) -> EvalResult<'static, ()> { - if self.is_aligned_to(align) { - Ok(()) - } else { - let mut best = self.offset; - let mut i = 1; - while best > 0 && (best & 1 == 0) { - best >>= 1; - i <<= 1; - } - Err(EvalError::AlignmentCheckFailed { - required: align, - has: i, - }) - } - } } #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] @@ -118,11 +99,11 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { bytes: Vec::new(), relocations: BTreeMap::new(), undef_mask: UndefMask::new(0), - align: 0, + align: 1, }; mem.alloc_map.insert(ZST_ALLOC_ID, alloc); // check that additional zst allocs work - debug_assert!(mem.allocate(0, 0).unwrap().points_to_zst()); + debug_assert!(mem.allocate(0, 1).unwrap().points_to_zst()); debug_assert!(mem.get(ZST_ALLOC_ID).is_ok()); mem } @@ -155,24 +136,22 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } pub fn allocate(&mut self, size: usize, align: usize) -> EvalResult<'tcx, Pointer> { + assert!(align != 0); if size == 0 { return Ok(Pointer::zst_ptr()); } - // make sure we can offset the result pointer by the worst possible alignment - // this allows cheaply checking for alignment directly in the pointer - let least_aligned_size = size + align; if self.memory_size - self.memory_usage < size { return Err(EvalError::OutOfMemory { - allocation_size: least_aligned_size, + allocation_size: size, memory_size: self.memory_size, memory_usage: self.memory_usage, }); } self.memory_usage += size; let alloc = Allocation { - bytes: vec![0; least_aligned_size], + bytes: vec![0; size], relocations: BTreeMap::new(), - undef_mask: UndefMask::new(least_aligned_size), + undef_mask: UndefMask::new(size), align: align, }; let id = self.next_id; @@ -180,15 +159,15 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { self.alloc_map.insert(id, alloc); Ok(Pointer { alloc_id: id, - // offset by the alignment, so larger accesses will fail - offset: align, + offset: 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: Pointer, new_size: usize, align: usize) -> EvalResult<'tcx, Pointer> { - if ptr.offset != self.get(ptr.alloc_id)?.align { + // TODO(solson): Report error about non-__rust_allocate'd pointer. + if ptr.offset != 0 { // TODO(solson): Report error about non-__rust_allocate'd pointer. return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); } @@ -197,27 +176,26 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } let size = self.get(ptr.alloc_id)?.bytes.len(); - let least_aligned_size = new_size + align; - if least_aligned_size > size { - let amount = least_aligned_size - size; + if new_size > size { + let amount = new_size - size; self.memory_usage += amount; let alloc = self.get_mut(ptr.alloc_id)?; alloc.bytes.extend(iter::repeat(0).take(amount)); alloc.undef_mask.grow(amount, false); - } else if size > least_aligned_size { + } else if size > new_size { // it's possible to cause miri to use arbitrary amounts of memory that aren't detectable // through the memory_usage value, by allocating a lot and reallocating to zero - self.memory_usage -= size - least_aligned_size; - self.clear_relocations(ptr.offset(least_aligned_size as isize), size - least_aligned_size)?; + self.memory_usage -= size - new_size; + self.clear_relocations(ptr.offset(new_size as isize), size - new_size)?; let alloc = self.get_mut(ptr.alloc_id)?; - alloc.bytes.truncate(least_aligned_size); - alloc.undef_mask.truncate(least_aligned_size); + alloc.bytes.truncate(new_size); + alloc.undef_mask.truncate(new_size); } Ok(Pointer { alloc_id: ptr.alloc_id, - offset: align, + offset: 0, }) } @@ -226,7 +204,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { if ptr.points_to_zst() { return Ok(()); } - if ptr.offset != self.get(ptr.alloc_id)?.align { + if ptr.offset != 0 { // TODO(solson): Report error about non-__rust_allocate'd pointer. return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); } @@ -251,6 +229,24 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { pub fn endianess(&self) -> layout::Endian { self.layout.endian } + + pub fn check_align(&self, ptr: Pointer, align: usize) -> EvalResult<'tcx, ()> { + let alloc = self.get(ptr.alloc_id)?; + if alloc.align < align { + return Err(EvalError::AlignmentCheckFailed { + has: alloc.align, + required: align, + }); + } + if ptr.offset % align == 0 { + Ok(()) + } else { + Err(EvalError::AlignmentCheckFailed { + has: ptr.offset % align, + required: align, + }) + } + } } /// Allocation accessors @@ -368,7 +364,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size]) } - fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> { + fn get_bytes(&self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &[u8]> { + self.check_align(ptr, align)?; if self.relocations(ptr, size)?.count() != 0 { return Err(EvalError::ReadPointerAsBytes); } @@ -376,7 +373,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { self.get_bytes_unchecked(ptr, size) } - fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &mut [u8]> { + fn get_bytes_mut(&mut self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &mut [u8]> { + self.check_align(ptr, align)?; self.clear_relocations(ptr, size)?; self.mark_definedness(ptr, size, true)?; self.get_bytes_unchecked_mut(ptr, size) @@ -385,11 +383,11 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { /// Reading and writing impl<'a, 'tcx> Memory<'a, 'tcx> { - pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<'tcx, ()> { + pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize, align: usize) -> EvalResult<'tcx, ()> { self.check_relocation_edges(src, size)?; let src_bytes = self.get_bytes_unchecked_mut(src, size)?.as_mut_ptr(); - let dest_bytes = self.get_bytes_mut(dest, size)?.as_mut_ptr(); + let dest_bytes = self.get_bytes_mut(dest, size, align)?.as_mut_ptr(); // SAFE: The above indexing would have panicked if there weren't at least `size` bytes // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and @@ -409,17 +407,17 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } pub fn read_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> { - self.get_bytes(ptr, size) + self.get_bytes(ptr, size, 1) } pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx, ()> { - let bytes = self.get_bytes_mut(ptr, src.len())?; + let bytes = self.get_bytes_mut(ptr, src.len(), 1)?; bytes.clone_from_slice(src); Ok(()) } pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: usize) -> EvalResult<'tcx, ()> { - let bytes = self.get_bytes_mut(ptr, count)?; + let bytes = self.get_bytes_mut(ptr, count, 1)?; for b in bytes { *b = val; } Ok(()) } @@ -465,8 +463,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } pub fn read_bool(&self, ptr: Pointer) -> EvalResult<'tcx, bool> { - ptr.check_align(self.layout.i1_align.abi() as usize)?; - let bytes = self.get_bytes(ptr, 1)?; + let bytes = self.get_bytes(ptr, 1, self.layout.i1_align.abi() as usize)?; match bytes[0] { 0 => Ok(false), 1 => Ok(true), @@ -475,42 +472,43 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } pub fn write_bool(&mut self, ptr: Pointer, b: bool) -> EvalResult<'tcx, ()> { - ptr.check_align(self.layout.i1_align.abi() as usize)?; - self.get_bytes_mut(ptr, 1).map(|bytes| bytes[0] = b as u8) + let align = self.layout.i1_align.abi() as usize; + self.get_bytes_mut(ptr, 1, align) + .map(|bytes| bytes[0] = b as u8) } - fn check_int_align(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, ()> { + fn int_align(&self, size: usize) -> EvalResult<'tcx, usize> { match size { - 1 => ptr.check_align(self.layout.i8_align.abi() as usize), - 2 => ptr.check_align(self.layout.i16_align.abi() as usize), - 4 => ptr.check_align(self.layout.i32_align.abi() as usize), - 8 => ptr.check_align(self.layout.i64_align.abi() as usize), + 1 => Ok(self.layout.i8_align.abi() as usize), + 2 => Ok(self.layout.i16_align.abi() as usize), + 4 => Ok(self.layout.i32_align.abi() as usize), + 8 => Ok(self.layout.i64_align.abi() as usize), _ => panic!("bad integer size"), } } pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, i64> { - self.check_int_align(ptr, size)?; - self.get_bytes(ptr, size).map(|b| read_target_int(self.endianess(), b).unwrap()) + let align = self.int_align(size)?; + self.get_bytes(ptr, size, align).map(|b| read_target_int(self.endianess(), b).unwrap()) } pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<'tcx, ()> { - self.check_int_align(ptr, size)?; + let align = self.int_align(size)?; let endianess = self.endianess(); - let b = self.get_bytes_mut(ptr, size)?; + let b = self.get_bytes_mut(ptr, size, align)?; write_target_int(endianess, b, n).unwrap(); Ok(()) } pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, u64> { - self.check_int_align(ptr, size)?; - self.get_bytes(ptr, size).map(|b| read_target_uint(self.endianess(), b).unwrap()) + let align = self.int_align(size)?; + self.get_bytes(ptr, size, align).map(|b| read_target_uint(self.endianess(), b).unwrap()) } pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<'tcx, ()> { - self.check_int_align(ptr, size)?; + let align = self.int_align(size)?; let endianess = self.endianess(); - let b = self.get_bytes_mut(ptr, size)?; + let b = self.get_bytes_mut(ptr, size, align)?; write_target_uint(endianess, b, n).unwrap(); Ok(()) } @@ -534,29 +532,29 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } pub fn write_f32(&mut self, ptr: Pointer, f: f32) -> EvalResult<'tcx, ()> { - ptr.check_align(self.layout.f32_align.abi() as usize)?; let endianess = self.endianess(); - let b = self.get_bytes_mut(ptr, 4)?; + let align = self.layout.f32_align.abi() as usize; + let b = self.get_bytes_mut(ptr, 4, align)?; write_target_f32(endianess, b, f).unwrap(); Ok(()) } pub fn write_f64(&mut self, ptr: Pointer, f: f64) -> EvalResult<'tcx, ()> { - ptr.check_align(self.layout.f64_align.abi() as usize)?; let endianess = self.endianess(); - let b = self.get_bytes_mut(ptr, 8)?; + let align = self.layout.f64_align.abi() as usize; + let b = self.get_bytes_mut(ptr, 8, align)?; write_target_f64(endianess, b, f).unwrap(); Ok(()) } pub fn read_f32(&self, ptr: Pointer) -> EvalResult<'tcx, f32> { - ptr.check_align(self.layout.f32_align.abi() as usize)?; - self.get_bytes(ptr, 4).map(|b| read_target_f32(self.endianess(), b).unwrap()) + self.get_bytes(ptr, 4, self.layout.f32_align.abi() as usize) + .map(|b| read_target_f32(self.endianess(), b).unwrap()) } pub fn read_f64(&self, ptr: Pointer) -> EvalResult<'tcx, f64> { - ptr.check_align(self.layout.f64_align.abi() as usize)?; - self.get_bytes(ptr, 8).map(|b| read_target_f64(self.endianess(), b).unwrap()) + self.get_bytes(ptr, 8, self.layout.f64_align.abi() as usize) + .map(|b| read_target_f64(self.endianess(), b).unwrap()) } } diff --git a/tests/compile-fail/oom.rs b/tests/compile-fail/oom.rs index d5f021bda704..83109a77e620 100644 --- a/tests/compile-fail/oom.rs +++ b/tests/compile-fail/oom.rs @@ -6,6 +6,6 @@ fn bar() { assert_eq!(x, 6); } -fn main() { //~ ERROR tried to allocate 8 more bytes, but only 0 bytes are free of the 0 byte memory +fn main() { //~ ERROR tried to allocate 4 more bytes, but only 0 bytes are free of the 0 byte memory bar(); } diff --git a/tests/compile-fail/oom2.rs b/tests/compile-fail/oom2.rs index 65ef0dd0b7da..63c51dbaa7d2 100644 --- a/tests/compile-fail/oom2.rs +++ b/tests/compile-fail/oom2.rs @@ -3,7 +3,7 @@ fn bar(i: i32) { if i < 1000 { - bar(i + 1) //~ ERROR tried to allocate 8 more bytes, but only 1 bytes are free of the 1000 byte memory + bar(i + 1) //~ ERROR tried to allocate 4 more bytes, but only 1 bytes are free of the 1000 byte memory //~^NOTE inside call to bar //~|NOTE inside call to bar //~|NOTE inside call to bar diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read.rs index 29355992e44c..f6a305840c24 100644 --- a/tests/compile-fail/out_of_bounds_read.rs +++ b/tests/compile-fail/out_of_bounds_read.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.get_unchecked(5) }; //~ ERROR: which has size 3 + let x = unsafe { *v.get_unchecked(5) }; //~ ERROR: which has size 2 panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index 388ed8b13063..5509a8346e55 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.get_unchecked(5) }; //~ ERROR: memory access of 6..7 outside bounds of allocation + let x = unsafe { *v.get_unchecked(5) }; //~ ERROR: memory access of 5..6 outside bounds of allocation panic!("this should never print: {}", x); } From f8cfc387fd3eef88033c93086ef4beb9d8e4f082 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 25 Jul 2016 12:30:35 +0200 Subject: [PATCH 8/8] address nits --- src/memory.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/memory.rs b/src/memory.rs index 91ae90da8b6f..d99d2c8132e3 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -168,7 +168,6 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { pub fn reallocate(&mut self, ptr: Pointer, new_size: usize, align: usize) -> EvalResult<'tcx, Pointer> { // TODO(solson): Report error about non-__rust_allocate'd pointer. if ptr.offset != 0 { - // TODO(solson): Report error about non-__rust_allocate'd pointer. return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); } if ptr.points_to_zst() { @@ -184,12 +183,11 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { alloc.bytes.extend(iter::repeat(0).take(amount)); alloc.undef_mask.grow(amount, false); } else if size > new_size { - // it's possible to cause miri to use arbitrary amounts of memory that aren't detectable - // through the memory_usage value, by allocating a lot and reallocating to zero self.memory_usage -= size - new_size; self.clear_relocations(ptr.offset(new_size as isize), size - new_size)?; let alloc = self.get_mut(ptr.alloc_id)?; alloc.bytes.truncate(new_size); + alloc.bytes.shrink_to_fit(); alloc.undef_mask.truncate(new_size); }