diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 73e52af4ec51..134702047522 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -172,48 +172,41 @@ fn main() { init_early_loggers(); // Parse our arguments and split them across `rustc` and `miri`. - let mut validate = true; - let mut stacked_borrows = true; - let mut check_alignment = true; - let mut communicate = false; - let mut ignore_leaks = false; - let mut seed: Option = None; - let mut tracked_pointer_tag: Option = None; - let mut tracked_call_id: Option = None; - let mut tracked_alloc_id: Option = None; + let mut miri_config = miri::MiriConfig::default(); let mut rustc_args = vec![]; - let mut crate_args = vec![]; let mut after_dashdash = false; - let mut excluded_env_vars = vec![]; for arg in env::args() { if rustc_args.is_empty() { // Very first arg: binary name. rustc_args.push(arg); } else if after_dashdash { // Everything that comes after `--` is forwarded to the interpreted crate. - crate_args.push(arg); + miri_config.args.push(arg); } else { match arg.as_str() { "-Zmiri-disable-validation" => { - validate = false; + miri_config.validate = false; } "-Zmiri-disable-stacked-borrows" => { - stacked_borrows = false; + miri_config.stacked_borrows = false; } "-Zmiri-disable-alignment-check" => { - check_alignment = false; + miri_config.check_alignment = miri::AlignmentCheck::None; + } + "-Zmiri-symbolic-alignment-check" => { + miri_config.check_alignment = miri::AlignmentCheck::Symbolic; } "-Zmiri-disable-isolation" => { - communicate = true; + miri_config.communicate = true; } "-Zmiri-ignore-leaks" => { - ignore_leaks = true; + miri_config.ignore_leaks = true; } "--" => { after_dashdash = true; } arg if arg.starts_with("-Zmiri-seed=") => { - if seed.is_some() { + if miri_config.seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); } let seed_raw = hex::decode(arg.strip_prefix("-Zmiri-seed=").unwrap()) @@ -234,10 +227,10 @@ fn main() { let mut bytes = [0; 8]; bytes[..seed_raw.len()].copy_from_slice(&seed_raw); - seed = Some(u64::from_be_bytes(bytes)); + miri_config.seed = Some(u64::from_be_bytes(bytes)); } arg if arg.starts_with("-Zmiri-env-exclude=") => { - excluded_env_vars + miri_config.excluded_env_vars .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { @@ -249,7 +242,7 @@ fn main() { ), }; if let Some(id) = miri::PtrId::new(id) { - tracked_pointer_tag = Some(id); + miri_config.tracked_pointer_tag = Some(id); } else { panic!("-Zmiri-track-pointer-tag requires a nonzero argument"); } @@ -263,7 +256,7 @@ fn main() { ), }; if let Some(id) = miri::CallId::new(id) { - tracked_call_id = Some(id); + miri_config.tracked_call_id = Some(id); } else { panic!("-Zmiri-track-call-id requires a nonzero argument"); } @@ -276,7 +269,7 @@ fn main() { err ), }; - tracked_alloc_id = Some(miri::AllocId(id)); + miri_config.tracked_alloc_id = Some(miri::AllocId(id)); } _ => { // Forward to rustc. @@ -287,19 +280,6 @@ fn main() { } debug!("rustc arguments: {:?}", rustc_args); - debug!("crate arguments: {:?}", crate_args); - let miri_config = miri::MiriConfig { - validate, - stacked_borrows, - check_alignment, - communicate, - ignore_leaks, - excluded_env_vars, - seed, - args: crate_args, - tracked_pointer_tag, - tracked_call_id, - tracked_alloc_id, - }; + debug!("crate arguments: {:?}", miri_config.args); run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }) } diff --git a/src/eval.rs b/src/eval.rs index cc5a6eb21fab..8e4604c3360a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -13,6 +13,16 @@ use rustc_target::abi::LayoutOf; use crate::*; +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum AlignmentCheck { + /// Do not check alignment. + None, + /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address. + Symbolic, + /// Check alignment on the actual physical integer address. + Int, +} + /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -20,8 +30,8 @@ pub struct MiriConfig { pub validate: bool, /// Determines if Stacked Borrows is enabled. pub stacked_borrows: bool, - /// Determines if alignment checking is enabled. - pub check_alignment: bool, + /// Controls alignment checking. + pub check_alignment: AlignmentCheck, /// Determines if communication with the host environment is enabled. pub communicate: bool, /// Determines if memory leaks should be ignored. @@ -45,7 +55,7 @@ impl Default for MiriConfig { MiriConfig { validate: true, stacked_borrows: true, - check_alignment: true, + check_alignment: AlignmentCheck::Int, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], diff --git a/src/lib.rs b/src/lib.rs index 816917081a8c..1b66d5ff6f31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, TerminationInfo, NonHaltingDiagnostic, }; -pub use crate::eval::{create_ecx, eval_main, MiriConfig}; +pub use crate::eval::{create_ecx, eval_main, AlignmentCheck, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, diff --git a/src/machine.rs b/src/machine.rs index 04bba6c33cdb..f2abb2ae0e7e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -128,7 +128,7 @@ pub struct MemoryExtra { tracked_alloc_id: Option, /// Controls whether alignment of memory accesses is being checked. - check_alignment: bool, + check_alignment: AlignmentCheck, } impl MemoryExtra { @@ -138,7 +138,7 @@ impl MemoryExtra { tracked_pointer_tag: Option, tracked_call_id: Option, tracked_alloc_id: Option, - check_alignment: bool, + check_alignment: AlignmentCheck, ) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id)))) @@ -336,7 +336,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn enforce_alignment(memory_extra: &MemoryExtra) -> bool { - memory_extra.check_alignment + memory_extra.check_alignment != AlignmentCheck::None + } + + #[inline(always)] + fn force_int_for_alignment_check(memory_extra: &Self::MemoryExtra) -> bool { + memory_extra.check_alignment == AlignmentCheck::Int } #[inline(always)] diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs index bdec0ff504bb..77eff5087dac 100644 --- a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-symbolic-alignment-check #![feature(core_intrinsics)] fn main() { diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index aa293a5d2167..a40db99a72a6 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -1,4 +1,4 @@ -// should find the bug even without these, but gets masked by optimizations +// should find the bug even without validation and stacked borrows, but gets masked by optimizations // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 #[repr(align(256))] @@ -15,5 +15,5 @@ fn main() { // Overwrite the data part of `ptr` so it points to `buf`. unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ ERROR accessing memory with alignment 4, but alignment 256 is required + let _ptr = &*ptr; //~ ERROR alignment 256 is required } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index 0a3b48dab5a0..3865d4578637 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -1,7 +1,9 @@ -// Even with intptrcast and without validation, we want to be *sure* to catch bugs -// that arise from pointers being insufficiently aligned. The only way to achieve -// that is not not let programs exploit integer information for alignment, so here -// we test that this is indeed the case. +// compile-flags: -Zmiri-symbolic-alignment-check +// With the symbolic alignment check, even with intptrcast and without +// validation, we want to be *sure* to catch bugs that arise from pointers being +// insufficiently aligned. The only way to achieve that is not not let programs +// exploit integer information for alignment, so here we test that this is +// indeed the case. // // See https://github.com/rust-lang/miri/issues/1074. fn main() { diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index 08104e917d21..a1240c90182a 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -15,5 +15,5 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR memory with alignment 1, but alignment 4 is required + let i = *p; //~ ERROR alignment 4 is required } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index 31f88c838149..beba47359b55 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -2,9 +2,9 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = &2u16; + let x = &2u8; let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. let _x = unsafe { *x }; - //~^ ERROR memory with alignment 2, but alignment 4 is required + //~^ ERROR alignment 4 is required } diff --git a/tests/run-pass/align.rs b/tests/run-pass/align.rs new file mode 100644 index 000000000000..b3d268f45e4b --- /dev/null +++ b/tests/run-pass/align.rs @@ -0,0 +1,11 @@ +// 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". +fn main() { + 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; } + } +}