Skip to content

Commit

Permalink
use real align_offset unless we symbolic alignment check is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Aug 16, 2020
1 parent 6647066 commit d4e5943
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 24 deletions.
35 changes: 18 additions & 17 deletions src/shims/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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.
Expand All @@ -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)
}
}
28 changes: 21 additions & 7 deletions tests/run-pass/align.rs
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down
File renamed without changes.

0 comments on commit d4e5943

Please sign in to comment.