make alignment check integer-based by default, and add an option to make it symbolic
This commit is contained in:
parent
ca9e988bdb
commit
cb985670c1
src
tests
compile-fail/unaligned_pointers
atomic_unaligned.rsdyn_alignment.rsintptrcast_alignment_check.rsreference_to_packed.rsunaligned_ptr_zst.rs
run-pass
@ -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<u64> = None;
|
||||
let mut tracked_pointer_tag: Option<miri::PtrId> = None;
|
||||
let mut tracked_call_id: Option<miri::CallId> = None;
|
||||
let mut tracked_alloc_id: Option<miri::AllocId> = 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 })
|
||||
}
|
||||
|
16
src/eval.rs
16
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![],
|
||||
|
@ -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,
|
||||
|
@ -128,7 +128,7 @@ pub struct MemoryExtra {
|
||||
tracked_alloc_id: Option<AllocId>,
|
||||
|
||||
/// 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<PtrId>,
|
||||
tracked_call_id: Option<CallId>,
|
||||
tracked_alloc_id: Option<AllocId>,
|
||||
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)]
|
||||
|
@ -1,3 +1,4 @@
|
||||
// compile-flags: -Zmiri-symbolic-alignment-check
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
fn main() {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
11
tests/run-pass/align.rs
Normal file
11
tests/run-pass/align.rs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user