Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to disable alignment check #1332

Merged
merged 5 commits into from
Apr 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 31 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,43 +160,51 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see
## Miri `-Z` flags and environment variables
[miri-flags]: #miri--z-flags-and-environment-variables

Several `-Z` flags are relevant for Miri:

* `-Zmiri-seed=<hex>` is a custom `-Z` flag added by Miri. It configures the
seed of the RNG that Miri uses to resolve non-determinism. This RNG is used
to pick base addresses for allocations. When isolation is enabled (the default),
this is also used to emulate system entropy. The default seed is 0.
**NOTE**: This entropy is not good enough for cryptographic use! Do not
generate secret keys in Miri or perform other kinds of cryptographic
operations that rely on proper random numbers.
* `-Zmiri-disable-validation` disables enforcing validity invariants, which are
enforced by default. This is mostly useful for debugging. It means Miri will
miss bugs in your program. However, this can also help to make Miri run
faster.
Miri adds its own set of `-Z` flags:

* `-Zmiri-disable-alignment-check` disables checking pointer alignment. This is
useful to avoid [false positives][alignment-false-positives]. However, setting
this flag means Miri could miss bugs in your program.
* `-Zmiri-disable-stacked-borrows` disables checking the experimental
[Stacked Borrows] aliasing rules. This can make Miri run faster, but it also
means no aliasing violations will be detected.
* `-Zmiri-disable-validation` disables enforcing validity invariants, which are
enforced by default. This is mostly useful to focus on other failures (such
as out-of-bounds accesses) first. Setting this flag means Miri will miss bugs
in your program. However, this can also help to make Miri run faster.
* `-Zmiri-disable-isolation` disables host isolation. As a consequence,
the program has access to host resources such as environment variables, file
systems, and randomness.
* `-Zmiri-ignore-leaks` disables the memory leak checker.
* `-Zmiri-env-exclude=<var>` keeps the `var` environment variable isolated from
the host. Can be used multiple times to exclude several variables. The `TERM`
environment variable is excluded by default.
the host so that it cannot be accessed by the program. Can be used multiple
times to exclude several variables. On Windows, the `TERM` environment
variable is excluded by default.
* `-Zmiri-ignore-leaks` disables the memory leak checker.
* `-Zmiri-seed=<hex>` configures the seed of the RNG that Miri uses to resolve
non-determinism. This RNG is used to pick base addresses for allocations.
When isolation is enabled (the default), this is also used to emulate system
entropy. The default seed is 0. **NOTE**: This entropy is not good enough
for cryptographic use! Do not generate secret keys in Miri or perform other
kinds of cryptographic operations that rely on proper random numbers.
* `-Zmiri-track-alloc-id=<id>` shows a backtrace when the given allocation is
being allocated. This helps in debugging memory leaks.
* `-Zmiri-track-pointer-tag=<tag>` shows a backtrace when the given pointer tag
is popped from a borrow stack (which is where the tag becomes invalid and any
future use of it will error). This helps you in finding out why UB is
happening and where in your code would be a good place to look for it.

[alignment-false-positives]: https://github.com/rust-lang/miri/issues/1074

Some native rustc `-Z` flags are also very relevant for Miri:

* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri
overrides the default to be `0`; be advised that using any higher level can
make Miri miss bugs in your program because they got optimized away.
* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic
functions. This is needed so that Miri can execute such functions, so Miri
sets this flag per default.
* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri
enables this per default because it is needed for validation.
* `-Zmiri-track-pointer-tag=<tag>` shows a backtrace when the given pointer tag
is popped from a borrow stack (which is where the tag becomes invalid and any
future use of it will error). This helps you in finding out why UB is
happening and where in your code would be a good place to look for it.
* `-Zmiri-track-alloc-id=<id>` shows a backtrace when the given allocation is
being allocated. This helps in debugging memory leaks.
enables this per default because it is needed for [Stacked Borrows].

Moreover, Miri recognizes some environment variables:

Expand Down
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4d1fbaccb822b6d52dc786589de7918d3c5effb1
47f49695dfb4fe9e584239fdc59c771887148a57
5 changes: 5 additions & 0 deletions src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ fn main() {
// 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;
Expand All @@ -152,6 +153,9 @@ fn main() {
"-Zmiri-disable-stacked-borrows" => {
stacked_borrows = false;
}
"-Zmiri-disable-alignment-check" => {
check_alignment = false;
}
"-Zmiri-disable-isolation" => {
communicate = true;
}
Expand Down Expand Up @@ -243,6 +247,7 @@ fn main() {
let miri_config = miri::MiriConfig {
validate,
stacked_borrows,
check_alignment,
communicate,
ignore_leaks,
excluded_env_vars,
Expand Down
1 change: 1 addition & 0 deletions src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ pub fn report_error<'tcx, 'mir>(
vec![
format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"),
format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs")
],
UndefinedBehavior(_) =>
vec![
Expand Down
4 changes: 4 additions & 0 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,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,
/// Determines if communication with the host environment is enabled.
pub communicate: bool,
/// Determines if memory leaks should be ignored.
Expand All @@ -40,6 +42,7 @@ impl Default for MiriConfig {
MiriConfig {
validate: true,
stacked_borrows: true,
check_alignment: true,
communicate: false,
ignore_leaks: false,
excluded_env_vars: vec![],
Expand Down Expand Up @@ -72,6 +75,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
config.stacked_borrows,
config.tracked_pointer_tag,
config.tracked_alloc_id,
config.check_alignment,
),
);
// Complete initialization.
Expand Down
17 changes: 15 additions & 2 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,19 @@ pub struct MemoryExtra {
/// An allocation ID to report when it is being allocated
/// (helps for debugging memory leaks).
tracked_alloc_id: Option<AllocId>,

/// Controls whether alignment of memory accesses is being checked.
check_alignment: bool,
}

impl MemoryExtra {
pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option<PtrId>, tracked_alloc_id: Option<AllocId>) -> Self {
pub fn new(
rng: StdRng,
stacked_borrows: bool,
tracked_pointer_tag: Option<PtrId>,
tracked_alloc_id: Option<AllocId>,
check_alignment: bool,
) -> Self {
let stacked_borrows = if stacked_borrows {
Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag))))
} else {
Expand All @@ -133,6 +142,7 @@ impl MemoryExtra {
extern_statics: FxHashMap::default(),
rng: RefCell::new(rng),
tracked_alloc_id,
check_alignment,
}
}

Expand Down Expand Up @@ -299,7 +309,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {

const GLOBAL_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::Global);

const CHECK_ALIGN: bool = true;
#[inline(always)]
fn enforce_alignment(memory_extra: &MemoryExtra) -> bool {
memory_extra.check_alignment
}

#[inline(always)]
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
Expand Down
10 changes: 5 additions & 5 deletions tests/compile-fail/unaligned_pointers/alignment.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
fn main() {
// miri always gives allocations the worst possible alignment, so a `u8` array is guaranteed
// to be at the virtual location 1 (so one byte offset from the ultimate alignemnt location 0)
let mut x = [0u8; 20];
let x_ptr: *mut u8 = &mut x[0];
let y_ptr = x_ptr as *mut u64;
let x_ptr: *mut u8 = x.as_mut_ptr();
// At least one of these is definitely unaligned.
// Currently, we guarantee to complain about the first one already (https://github.com/rust-lang/miri/issues/1074).
unsafe {
*y_ptr = 42; //~ ERROR accessing memory with alignment 1, but alignment
*(x_ptr as *mut u64) = 42; //~ ERROR accessing memory with alignment 1, but alignment
*(x_ptr.add(1) as *mut u64) = 42;
}
panic!("unreachable in miri");
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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() {
let x = &mut [0u8; 3];
let base_addr = x as *mut _ as usize;
Expand Down
11 changes: 11 additions & 0 deletions tests/run-pass/disable-alignment-check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// compile-flags: -Zmiri-disable-alignment-check

fn main() {
let mut x = [0u8; 20];
let x_ptr: *mut u8 = x.as_mut_ptr();
// At least one of these is definitely unaligned.
unsafe {
*(x_ptr as *mut u64) = 42;
*(x_ptr.add(1) as *mut u64) = 42;
}
}