use real align_offset unless we symbolic alignment check is enabled

This commit is contained in:
Ralf Jung 2020-08-16 18:16:34 +02:00
parent 664706662f
commit d4e5943259
4 changed files with 41 additions and 24 deletions

View file

@ -13,8 +13,6 @@ pub mod tls;
// End module management, begin local code
use std::convert::TryFrom;
use log::trace;
use rustc_middle::{mir, ty};
@ -37,8 +35,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// There are some more lang items we want to hook that CTFE does not hook (yet).
if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
let &[ptr, align] = check_arg_count(args)?;
this.align_offset(ptr, align, ret, unwind)?;
return Ok(None);
if this.align_offset(ptr, align, ret, unwind)? {
return Ok(None);
}
}
// Try to see if we can do something about foreign items.
@ -56,46 +55,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Ok(Some(&*this.load_mir(instance.def, None)?))
}
/// Returns `true` if the computation was performed, and `false` if we should just evaluate
/// the actual MIR of `align_offset`.
fn align_offset(
&mut self,
ptr_op: OpTy<'tcx, Tag>,
align_op: OpTy<'tcx, Tag>,
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
) -> InterpResult<'tcx, bool> {
let this = self.eval_context_mut();
let (dest, ret) = ret.unwrap();
if this.memory.extra.check_alignment != AlignmentCheck::Symbolic {
// Just use actual implementation.
return Ok(false);
}
let req_align = this
.force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?;
// Stop if the alignment is not a power of two.
if !req_align.is_power_of_two() {
return this.start_panic("align_offset: align is not a power-of-two", unwind);
this.start_panic("align_offset: align is not a power-of-two", unwind)?;
return Ok(true); // nothing left to do
}
let ptr_scalar = this.read_scalar(ptr_op)?.check_init()?;
// Default: no result.
let mut result = this.machine_usize_max();
if let Ok(ptr) = this.force_ptr(ptr_scalar) {
// Only do anything if we can identify the allocation this goes to.
let cur_align =
this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes();
if u128::from(cur_align) >= req_align {
// If the allocation alignment is at least the required alignment we use the
// libcore implementation.
// FIXME: is this correct in case of truncation?
result = u64::try_from(
(this.force_bits(ptr_scalar, this.pointer_size())? as *const i8)
.align_offset(usize::try_from(req_align).unwrap())
).unwrap();
// real implementation.
return Ok(false);
}
}
// Return result, and jump to caller.
this.write_scalar(Scalar::from_machine_usize(result, this), dest)?;
// Return error result (usize::MAX), and jump to caller.
this.write_scalar(Scalar::from_machine_usize(this.machine_usize_max(), this), dest)?;
this.go_to_block(ret);
Ok(())
Ok(true)
}
}

View file

@ -1,11 +1,25 @@
// This manually makes sure that we have a pointer with the proper alignment.
// Do this a couple times in a loop because it may work "by chance".
/// This manually makes sure that we have a pointer with the proper alignment.
fn manual_alignment() {
let x = &mut [0u8; 3];
let base_addr = x as *mut _ as usize;
let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 };
let u16_ptr = base_addr_aligned as *mut u16;
unsafe { *u16_ptr = 2; }
}
/// Test standard library `align_to`.
fn align_to() {
const LEN: usize = 128;
let buf = &[0u8; LEN];
let (l, m, r) = unsafe { buf.align_to::<i32>() };
assert!(m.len()*4 >= LEN-4);
assert!(l.len() + r.len() <= 4);
}
fn main() {
// Do this a couple times in a loop because it may work "by chance".
for _ in 0..10 {
let x = &mut [0u8; 3];
let base_addr = x as *mut _ as usize;
let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 };
let u16_ptr = base_addr_aligned as *mut u16;
unsafe { *u16_ptr = 2; }
manual_alignment();
align_to();
}
}

View file

@ -1,3 +1,5 @@
// compile-flags: -Zmiri-symbolic-alignment-check
fn test_align_offset() {
let d = Box::new([0u32; 4]);
// Get u8 pointer to base