Miri gives error on my local machine, but doesn't on playground

cargo miri run in my local machine fails with

error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required 8 byte alignment but found 1)
 --> src/main.rs:6:22
6 |         let valref = &*(v.as_ptr() as *const usize);
  |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 8 byte alignment but found 1)

even when I give -Zmiri-disable-alignment-check and adjust -Zmiri-seed to get the correct alignment.

But running miri on the same code in the playground does not give any errors.

Problematic code

fn main() {
    unsafe {
        let mut v: Vec<u8> = Vec::new();
        let val: usize = 123;
        let valref = &*(v.as_ptr() as *const usize);
        println!("val: {}", *valref);

unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
    std::slice::from_raw_parts((p as *const T) as *const u8, std::mem::size_of::<T>())



val: 123


   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 1.80s
     Running `target/debug/playground`

More Related Questions:

  1. Does Miri forbid creating references out of byte slice even if the alignment is actually correct?
  2. Is there a way to set minimum alignment for Miri's allocator?

The Playground miri also reports UB if you change the first line to

let mut v: Vec<u8> = vec![0];

thereby forcing an upfront allocation. (I had the hunch this could change the behavior.)

That's probably not the case. If Miri says the pointer is not correctly aligned, then it isn't, in fact, correctly aligned. Miri doesn't have false positives.*

If you want to correctly and soundly convert between pointers to POD types, you have a couple options that are much, much better and safer than manually type-punning through raw pointers:

  1. Just copy the bytes. The standard library offers byte-by-byte constructors for most of the types you'll care about.
  2. Use bytemuck which provides out-of-the-box safe abstractions for POD types.
  3. If you are seeking performance improvements, use <[_]>::align_to(). This is still unsafe, but it at least gets the alignment right.

*Some people debate this, asserting that some of the Miri positives are merely "not yet settled" in the language definition. I think the principled and correct way is to treat those as UB, pretty much by definition – let's not start/continue this debate here, please.

Actually, miri has a flag -Zmiri-symbolic-alignment-check which prevents "discovering" that a pointer is more aligned than is required. (And this is documented as causing false positives when code does alignment checks itself.) This is (part of) the reason align_to is allowed to "fail" to provide a maximal middle part.

  • -Zmiri-symbolic-alignment-check makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a program passes the alignment check by pure chance, because things "happened to be" sufficiently aligned -- there is no UB in this execution but there would be UB in others. To avoid such cases, the symbolic alignment check only takes into account the requested alignment of the relevant allocation, and the offset into that allocation. This avoids missing such bugs, but it also incurs some false positives when the code does manual integer arithmetic to ensure alignment. (The standard library align_to method works fine in both modes; under symbolic alignment it only fills the middle slice when the allocation guarantees sufficient alignment.)

Based on the described behavior, my first guess would be that this flag is getting set somehow (MIRIFLAGS?), and doesn't get unset by -Zmiri-disable-alignment-check; with the alignment check disabled, this error shouldn't happen at all.

  • -Zmiri-disable-alignment-check disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is unsound.

There's not a direct way, as far as I'm aware. You can, however, set a #[global_allocator] which rounds up align/size to whatever base alignment you want to model this.

1 Like

I don't think this contradicts what I wrote. The allocation itself was never properly aligned, so using it was always incorrect. It could have dynamically led to UB upon any future execution, as it only happened to work by pure chance. I don't think working by pure chance counts as "properly aligned".

It's at best not reliable, at worst UB, and the subject of the scrutiny should not be what happened to "work" upon one particular execution; it should be how the code must be modified to achieve a reliably correct execution at all times.

However, the code in the OP never performs any manual aligning or even alignment checks itself. I guess this definition of a "false" positive is not very useful, specifically in cases where such "obvious"(ly wrong) code is being run under Miri. Here, the Miri error does point out a legitimate problem in the code, and it is most definitely the code that should be fixed, not Miri's definition of an error.

Thanks for the reply.
Interesting that vec![0] changes the behavior.

Miri seems to complain even if I check alignment before converting to a reference.
I don't know how to set -Zmiri-seed on playground, but I get the error on my local machine with a seed that meets the alignment.

I know the code is fundamentally unsafe, but there is a large piece of code that would take much time to fix, and I want to find other bugs first if I can, ignoring the alignment because the system allocator has minimum alignment anyways.

Interestingly, using global_allocator to force layout.align() to 8 seems to work!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.