rust-lang / miri

An interpreter for Rust's mid-level intermediate representation
Apache License 2.0
4.66k stars 349 forks source link

u64 -> [u8; 8] transmute triggers spurious alignment error #184

Closed dwrensha closed 7 years ago

dwrensha commented 7 years ago
// test.rs

pub fn main() {
    let bytes: [u8; 8] = unsafe { ::std::mem::transmute(0u64) };
    let _: &[u8] = &bytes;
}
$ cargo run --bin miri -- test.rs
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/miri test.rs`
error: tried to access memory with alignment 1, but alignment 8 is required
 --> test.rs:5:20
  |
5 |     let _: &[u8] = &bytes;
  |                    ^^^^^^
  |
note: inside call to main
 --> test.rs:3:1
  |
3 | / pub fn main() {
4 | |     let bytes: [u8; 8] = unsafe { ::std::mem::transmute(0u64) };
5 | |     let _: &[u8] = &bytes;
6 | | }
  | |_^

error: aborting due to previous error(s)
dwrensha commented 7 years ago

The byteorder crate depends on this kind of transmute working.

dwrensha commented 7 years ago

Related to #113.

oli-obk commented 7 years ago

Can you dump the miri trace? Use the envto var MIRI_LOG=trace to produce it

dwrensha commented 7 years ago
trace ``` $ MIRI_LOG=trace cargo run --bin miri -- test.rs Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/miri test.rs` TRACE:miri::eval_context: load mir Item(DefId { krate: CrateNum(0), node: DefIndex(3) => test/8cd878b::main[0] }) TRACE:miri::step: StorageLive(_1) TRACE:miri::eval_context: _1: is dead TRACE:miri::eval_context: _1 is now live TRACE:miri::step: _1 = const std::intrinsics::transmute(const 0u64) -> bb1 TRACE:miri::eval_context: _1: Undef DEBUG:miri::eval_context: resolve(def_id=DefId { krate: CrateNum(2), node: DefIndex(2147484730) => core/ce488d1::intrinsics[0]::[1]::transmute[0] }, substs=Slice([u64, [u8; 8]])) DEBUG:miri::eval_context: apply_param_substs(param_substs=Slice([u64, [u8; 8]]), value=unsafe extern "rust-intrinsic" fn(T) -> U {std::intrinsics::transmute::}) DEBUG:miri::eval_context: => intrinsic DEBUG:miri::eval_context: resolve(def_id=DefId { krate: CrateNum(2), node: DefIndex(2147484730) => core/ce488d1::intrinsics[0]::[1]::transmute[0] }, substs=Slice([u64, [u8; 8]])) = std::intrinsics::transmute:: - intrinsic TRACE:miri::terminator: eval_fn_call: Instance { def: Intrinsic( DefId { krate: CrateNum(2), node: DefIndex(2147484730) => core/ce488d1::intrinsics[0]::[1]::transmute[0] } ), substs: Slice( [ u64, [u8; 8] ] ) } TRACE:miri::eval_context: _1: Bytes(0) TRACE:miri::step: // bb1 TRACE:miri::step: StorageLive(_2) TRACE:miri::eval_context: _2: is dead TRACE:miri::eval_context: _2 is now live TRACE:miri::step: StorageLive(_3) TRACE:miri::eval_context: _3: is dead TRACE:miri::eval_context: _3 is now live TRACE:miri::step: StorageLive(_4) TRACE:miri::eval_context: _4: is dead TRACE:miri::eval_context: _4 is now live TRACE:miri::step: _4 = &_1 TRACE:miri::eval_context: _4: Undef TRACE:miri::eval_context: _1: Bytes(0) error: tried to access memory with alignment 1, but alignment 8 is required --> test.rs:5:20 | 5 | let _: &[u8] = &bytes; | ^^^^^^ | note: inside call to main --> test.rs:3:1 | 3 | / pub fn main() { 4 | | let bytes: [u8; 8] = unsafe { ::std::mem::transmute(0u64) }; 5 | | let _: &[u8] = &bytes; 6 | | } | |_^ error: aborting due to previous error(s) ```
dwrensha commented 7 years ago

force_allocation() sees [u8; 8] and makes an allocation of alignment 1. Then it calls write_value_to_ptr() to populate the new allocation with the existing u64, which has size 8. In write_uint() and then get_bytes_mut() the alignment is then taken and checked as 8, triggering the error.

oli-obk commented 7 years ago

OK... we should make transmutes between different alignments always allocate, and use mark_packed.