From d4e5943259de7573556711ed6496c409dd754ea3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 18:16:34 +0200 Subject: [PATCH] use real align_offset unless we symbolic alignment check is enabled --- src/shims/mod.rs | 35 ++++++++++--------- tests/run-pass/align.rs | 28 +++++++++++---- ...ign_offset.rs => align_offset_symbolic.rs} | 2 ++ ...et.stdout => align_offset_symbolic.stdout} | 0 4 files changed, 41 insertions(+), 24 deletions(-) rename tests/run-pass/{align_offset.rs => align_offset_symbolic.rs} (98%) rename tests/run-pass/{align_offset.stdout => align_offset_symbolic.stdout} (100%) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 05dd4059eb..eab27496cb 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -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, - ) -> 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) } } diff --git a/tests/run-pass/align.rs b/tests/run-pass/align.rs index b3d268f45e..81e7e8c7cc 100644 --- a/tests/run-pass/align.rs +++ b/tests/run-pass/align.rs @@ -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::() }; + 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(); } } diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset_symbolic.rs similarity index 98% rename from tests/run-pass/align_offset.rs rename to tests/run-pass/align_offset_symbolic.rs index f921634647..70b2e00896 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset_symbolic.rs @@ -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 diff --git a/tests/run-pass/align_offset.stdout b/tests/run-pass/align_offset_symbolic.stdout similarity index 100% rename from tests/run-pass/align_offset.stdout rename to tests/run-pass/align_offset_symbolic.stdout