diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 3ca71e9b90c2..df101739ed91 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use syntax::attr; @@ -111,7 +111,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if size == 0 { self.write_null(dest, dest_ty)?; } else { - let align = self.memory.pointer_size(); + let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } @@ -307,7 +307,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // +1 for the null terminator let value_copy = self.memory.allocate( (value.len() + 1) as u64, - 1, + Align::from_bytes(1, 1).unwrap(), Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; @@ -369,6 +369,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "sysconf" => { let name = self.value_to_primval(args[0])?.to_u64()?; + let name_align = self.layout_of(args[0].ty)?.align; + trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ @@ -387,7 +389,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' Some(ptr) => ptr, None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, }; - let val = self.value_to_primval(ValTy { value: Value::ByRef(val), ty: args[0].ty })?.to_u64()?; + let val = self.value_to_primval(ValTy { value: Value::ByRef(val, name_align), + ty: args[0].ty })?.to_u64()?; if val == name { result = Some(path_value); break; @@ -406,6 +409,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { let key_ptr = self.into_ptr(args[0].value)?; + let key_align = self.layout_of(args[0].ty)?.align; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { @@ -427,6 +431,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } self.memory.write_primval( key_ptr.to_ptr()?, + key_align, PrimVal::Bytes(key), key_size.bytes(), false, @@ -559,7 +564,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; + let ptr = self.memory.allocate(size, + Align::from_bytes(align, align).unwrap(), + Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::heap::::__rust_alloc_zeroed" => { @@ -571,7 +578,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; + let ptr = self.memory.allocate(size, + Align::from_bytes(align, align).unwrap(), + Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, size)?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } @@ -587,7 +596,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } self.memory.deallocate( ptr, - Some((old_size, align)), + Some((old_size, Align::from_bytes(align, align).unwrap())), MemoryKind::Rust.into(), )?; } @@ -609,9 +618,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let new_ptr = self.memory.reallocate( ptr, old_size, - old_align, + Align::from_bytes(old_align, old_align).unwrap(), new_size, - new_align, + Align::from_bytes(new_align, new_align).unwrap(), MemoryKind::Rust.into(), )?; self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 705c33252339..3357f0bba392 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -3,7 +3,7 @@ use rustc::traits::Reveal; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer, AccessKind, PtrAndAlign}; +use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -87,8 +87,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "atomic_load_acq" | "volatile_load" => { let ptr = self.into_ptr(args[0].value)?; + let align = self.layout_of(args[0].ty)?.align; + let valty = ValTy { - value: Value::by_ref(ptr), + value: Value::ByRef(ptr, align), ty: substs.type_at(0), }; self.write_value(valty, dest)?; @@ -99,8 +101,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "atomic_store_rel" | "volatile_store" => { let ty = substs.type_at(0); + let align = self.layout_of(ty)?.align; let dest = self.into_ptr(args[0].value)?; - self.write_value_to_ptr(args[1].value, dest, ty)?; + self.write_value_to_ptr(args[1].value, dest, align, ty)?; } "atomic_fence_acq" => { @@ -109,9 +112,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' _ if intrinsic_name.starts_with("atomic_xchg") => { let ty = substs.type_at(0); + let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; let change = self.value_to_primval(args[1])?; - let old = self.read_value(ptr, ty)?; + let old = self.read_value(ptr, align, ty)?; let old = match old { Value::ByVal(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), @@ -119,7 +123,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; self.write_primval(dest, old, ty)?; self.write_primval( - Place::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr, align), change, ty, )?; @@ -127,10 +131,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' _ if intrinsic_name.starts_with("atomic_cxchg") => { let ty = substs.type_at(0); + let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; let expect_old = self.value_to_primval(args[1])?; let change = self.value_to_primval(args[2])?; - let old = self.read_value(ptr, ty)?; + let old = self.read_value(ptr, align, ty)?; let old = match old { Value::ByVal(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), @@ -143,7 +148,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; self.write_value(valty, dest)?; self.write_primval( - Place::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr, dest_layout.align), change, ty, )?; @@ -175,9 +180,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { let ty = substs.type_at(0); + let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; let change = self.value_to_primval(args[1])?; - let old = self.read_value(ptr, ty)?; + let old = self.read_value(ptr, align, ty)?; let old = match old { Value::ByVal(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), @@ -196,7 +202,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Place::from_primval_ptr(ptr), val, ty)?; + self.write_primval(Place::from_primval_ptr(ptr, dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -210,14 +216,16 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if count * elem_size != 0 { // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. // Also see the write_bytes intrinsic. - let elem_align = elem_layout.align.abi(); + let elem_align = elem_layout.align; let src = self.into_ptr(args[0].value)?; + let src_align = self.layout_of(args[0].ty)?.align; let dest = self.into_ptr(args[1].value)?; self.memory.copy( src, + src_align, dest, - count * elem_size, elem_align, + count * elem_size, intrinsic_name.ends_with("_nonoverlapping"), )?; } @@ -241,7 +249,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = self.into_ptr(args[0].value)?; - let place = Place::from_primval_ptr(adt_ptr); + let adt_align = self.layout_of(args[0].ty)?.align; + let place = Place::from_primval_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, ty)?; self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; } @@ -312,7 +321,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let size = dest_layout.size.bytes(); let init = |this: &mut Self, val: Value| { let zero_val = match val { - Value::ByRef(PtrAndAlign { ptr, .. }) => { + Value::ByRef(ptr, _) => { // These writes have no alignment restriction anyway. this.memory.write_repeat(ptr, 0, size)?; val @@ -326,7 +335,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let ptr = this.alloc_ptr(dest_layout.ty)?; let ptr = Pointer::from(PrimVal::Ptr(ptr)); this.memory.write_repeat(ptr, 0, size)?; - Value::by_ref(ptr) + Value::ByRef(ptr, dest_layout.align) } } } @@ -340,12 +349,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, init)?, Place::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, + ptr: ptr, + align: _align, extra: PlaceExtra::None, } => self.memory.write_repeat(ptr, 0, size)?, - Place::Ptr { .. } => { - bug!("init intrinsic tried to write to fat or unaligned ptr target") - } + _ => bug!("TODO"), } } @@ -367,7 +375,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "move_val_init" => { let ty = substs.type_at(0); let ptr = self.into_ptr(args[0].value)?; - self.write_value_to_ptr(args[1].value, ptr, ty)?; + let align = self.layout_of(args[0].ty)?.align; + self.write_value_to_ptr(args[1].value, ptr, align, ty)?; } "needs_drop" => { @@ -533,14 +542,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "transmute" => { let src_ty = substs.type_at(0); + let src_align = self.layout_of(src_ty)?.align; let ptr = self.force_allocation(dest)?.to_ptr()?; - self.write_maybe_aligned_mut( - /*aligned*/ - false, - |ectx| { - ectx.write_value_to_ptr(args[0].value, ptr.into(), src_ty) - }, - )?; + let dest_align = self.layout_of(substs.type_at(1))?.align; + self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty); } "unchecked_shl" => { @@ -612,7 +617,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "uninit" => { let size = dest_layout.size.bytes(); let uninit = |this: &mut Self, val: Value| match val { - Value::ByRef(PtrAndAlign { ptr, .. }) => { + Value::ByRef(ptr, _) => { this.memory.mark_definedness(ptr, size, false)?; Ok(val) } @@ -621,12 +626,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, Place::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, + ptr: ptr, + align: _align, extra: PlaceExtra::None, } => self.memory.mark_definedness(ptr, size, false)?, - Place::Ptr { .. } => { - bug!("uninit intrinsic tried to write to fat or unaligned ptr target") - } + _ => bug!("todo"), } } @@ -639,7 +643,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) - self.memory.check_align(ptr, ty_layout.align.abi(), Some(AccessKind::Write))?; + self.memory.check_align(ptr, ty_layout.align)?; self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; } } diff --git a/miri/lib.rs b/miri/lib.rs index d4c211e1fd95..d458a3c47e8c 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -20,7 +20,6 @@ extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; use rustc::mir; use rustc::traits; @@ -87,7 +86,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Return value let size = ecx.tcx.data_layout.pointer_size.bytes(); - let align = ecx.tcx.data_layout.pointer_align.abi(); + let align = ecx.tcx.data_layout.pointer_align; let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); @@ -96,7 +95,7 @@ pub fn eval_main<'a, 'tcx: 'a>( start_instance, start_mir.span, start_mir, - Place::from_ptr(ret_ptr), + Place::from_ptr(ret_ptr, align), StackPopCleanup::None, )?; @@ -126,8 +125,9 @@ pub fn eval_main<'a, 'tcx: 'a>( let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_cached(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); - let foo_ptr = ecx.memory.allocate(ptr_size * 1, ptr_size, None)?; - ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?; + let ptr_align = ecx.tcx.data_layout.pointer_align; + let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; + ecx.memory.write_primval(foo_ptr, ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -158,7 +158,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) } - let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default(), Substs::empty()); + let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default()); match run_main(&mut ecx, main_id, start_wrapper) { Ok(()) => { let leaks = ecx.memory().leak_report(); @@ -310,22 +310,20 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { // FIXME: check that it's `#[linkage = "extern_weak"]` trace!("Initializing an extern global with NULL"); let ptr_size = ecx.memory.pointer_size(); + let ptr_align = ecx.tcx.data_layout.pointer_align; let ptr = ecx.memory.allocate( ptr_size, - ptr_size, + ptr_align, None, )?; - ecx.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?; + ecx.memory.write_ptr_sized_unsigned(ptr, ptr_align, PrimVal::Bytes(0))?; ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?; ecx.tcx.interpret_interner.borrow_mut().cache( GlobalId { instance, promoted: None, }, - PtrAndAlign { - ptr: ptr.into(), - aligned: true, - }, + ptr.into(), ); Ok(()) } diff --git a/miri/operator.rs b/miri/operator.rs index e70f1b12628a..919997a5217c 100644 --- a/miri/operator.rs +++ b/miri/operator.rs @@ -153,7 +153,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' map_to_primval(left.overflowing_offset(right as u64, self)), BitAnd if !signed => { - let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align - 1); + let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there diff --git a/miri/validation.rs b/miri/validation.rs index 52f0c24bd6d1..843dcd4041d7 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -509,7 +509,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // Check alignment and non-NULLness let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; let ptr = self.into_ptr(val)?; - self.memory.check_align(ptr, align.abi(), None)?; + self.memory.check_align(ptr, align)?; // Recurse let pointee_place = self.val_to_place(val, pointee_ty)?; @@ -567,7 +567,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // Tracking the same state for locals not backed by memory would just duplicate too // much machinery. // FIXME: We ignore alignment. - let (ptr, extra) = self.force_allocation(query.place.1)?.to_ptr_extra_aligned(); + let (ptr, _, extra) = self.force_allocation(query.place.1)?.to_ptr_align_extra(); // Determine the size // FIXME: Can we reuse size_and_align_of_dst for Places? let layout = self.layout_of(query.ty)?;