From d21b601b6e89746378e020a1e4a6f3d7e98bc5c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Aug 2022 15:59:27 -0400 Subject: [PATCH] make Miri build again with rustc provenance changes --- src/diagnostics.rs | 7 +-- src/helpers.rs | 2 +- src/machine.rs | 15 ++++++ src/shims/foreign_items.rs | 8 +-- src/shims/unix/fs.rs | 2 +- src/shims/windows/dlsym.rs | 3 +- tests/fail/copy_half_a_pointer.rs | 21 ++++++++ tests/fail/copy_half_a_pointer.stderr | 14 +++++ tests/fail/intrinsics/raw_eq_on_ptr.rs | 3 +- tests/fail/intrinsics/raw_eq_on_ptr.stderr | 7 +-- tests/fail/invalid_int.rs | 1 + tests/fail/reading_half_a_pointer.rs | 3 +- tests/fail/reading_half_a_pointer.stderr | 9 ++-- tests/fail/transmute_fat1.rs | 13 ----- tests/fail/transmute_fat1.stderr | 15 ------ tests/fail/validity/invalid_bool_uninit.rs | 4 +- .../fail/validity/invalid_bool_uninit.stderr | 4 +- tests/fail/validity/invalid_char_uninit.rs | 4 +- .../fail/validity/invalid_char_uninit.stderr | 4 +- tests/fail/validity/invalid_fnptr_uninit.rs | 4 +- .../fail/validity/invalid_fnptr_uninit.stderr | 4 +- .../validity/ptr_integer_array_transmute.rs | 4 -- .../ptr_integer_array_transmute.stderr | 15 ------ tests/fail/validity/uninit_float.rs | 5 +- tests/fail/validity/uninit_float.stderr | 6 +-- tests/fail/validity/uninit_integer.rs | 4 +- tests/fail/validity/uninit_integer.stderr | 6 +-- tests/fail/validity/uninit_raw_ptr.rs | 5 +- tests/fail/validity/uninit_raw_ptr.stderr | 6 +-- tests/pass/transmute_fat.rs | 10 ---- tests/pass/transmute_ptr.rs | 52 +++++++++++++++++++ 31 files changed, 158 insertions(+), 102 deletions(-) create mode 100644 tests/fail/copy_half_a_pointer.rs create mode 100644 tests/fail/copy_half_a_pointer.stderr delete mode 100644 tests/fail/transmute_fat1.rs delete mode 100644 tests/fail/transmute_fat1.stderr delete mode 100644 tests/fail/validity/ptr_integer_array_transmute.rs delete mode 100644 tests/fail/validity/ptr_integer_array_transmute.stderr delete mode 100644 tests/pass/transmute_fat.rs create mode 100644 tests/pass/transmute_ptr.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 74d2fe2680..8ba2995662 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -226,13 +226,14 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind() { Unsupported( UnsupportedOpInfo::ThreadLocalStatic(_) | - UnsupportedOpInfo::ReadExternStatic(_) + UnsupportedOpInfo::ReadExternStatic(_) | + UnsupportedOpInfo::PartialPointerOverwrite(_) | // we make memory uninit instead + UnsupportedOpInfo::ReadPointerAsBytes ) => panic!("Error should never be raised by Miri: {kind:?}", kind = e.kind()), Unsupported( UnsupportedOpInfo::Unsupported(_) | - UnsupportedOpInfo::PartialPointerOverwrite(_) | - UnsupportedOpInfo::ReadPointerAsBytes + UnsupportedOpInfo::PartialPointerCopy(_) ) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) diff --git a/src/helpers.rs b/src/helpers.rs index 92139d9aa2..57c9fd3389 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -757,7 +757,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Step 2: get the bytes. - this.read_bytes_ptr(ptr, len) + this.read_bytes_ptr_strip_provenance(ptr, len) } fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { diff --git a/src/machine.rs b/src/machine.rs index 3be4d1d1b5..b7624ac592 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -205,6 +205,21 @@ impl interpret::Provenance for Provenance { Provenance::Wildcard => None, } } + + fn join(left: Option, right: Option) -> Option { + match (left, right) { + // If both are the *same* concrete tag, that is the result. + ( + Some(Provenance::Concrete { alloc_id: left_alloc, sb: left_sb }), + Some(Provenance::Concrete { alloc_id: right_alloc, sb: right_sb }), + ) if left_alloc == right_alloc && left_sb == right_sb => left, + // If one side is a wildcard, the best possible outcome is that it is equal to the other + // one, and we use that. + (Some(Provenance::Wildcard), o) | (o, Some(Provenance::Wildcard)) => o, + // Otherwise, fall back to `None`. + _ => None, + } + } } impl fmt::Debug for ProvenanceExtra { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 117e0933dd..b94b6bbb2b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -560,8 +560,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { - let left_bytes = this.read_bytes_ptr(left, n)?; - let right_bytes = this.read_bytes_ptr(right, n)?; + let left_bytes = this.read_bytes_ptr_strip_provenance(left, n)?; + let right_bytes = this.read_bytes_ptr_strip_provenance(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -583,7 +583,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = val as u8; if let Some(idx) = this - .read_bytes_ptr(ptr, Size::from_bytes(num))? + .read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))? .iter() .rev() .position(|&c| c == val) @@ -606,7 +606,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = val as u8; let idx = this - .read_bytes_ptr(ptr, Size::from_bytes(num))? + .read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))? .iter() .position(|&c| c == val); if let Some(idx) = idx { diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index d3f4f5ef54..06cd533626 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -761,7 +761,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - let bytes = this.read_bytes_ptr(buf, Size::from_bytes(count))?; + let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?; let result = file_descriptor.write(communicate, bytes)?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 5cbfecb889..8749ed91bb 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -78,7 +78,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; + let buf_cont = + this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; let res = if this.machine.mute_stdout_stderr { Ok(buf_cont.len()) } else if handle == -11 { diff --git a/tests/fail/copy_half_a_pointer.rs b/tests/fail/copy_half_a_pointer.rs new file mode 100644 index 0000000000..e1dcdda7fd --- /dev/null +++ b/tests/fail/copy_half_a_pointer.rs @@ -0,0 +1,21 @@ +//@normalize-stderr-test: "\+0x[48]" -> "+HALF_PTR" +#![allow(dead_code)] + +// We use packed structs to get around alignment restrictions +#[repr(packed)] +struct Data { + pad: u8, + ptr: &'static i32, +} + +static G: i32 = 0; + +fn main() { + let mut d = Data { pad: 0, ptr: &G }; + + // Get a pointer to the beginning of the Data struct (one u8 byte, then the pointer bytes). + let d_alias = &mut d as *mut _ as *mut *const u8; + unsafe { + let _x = d_alias.read_unaligned(); //~ERROR: unable to copy parts of a pointer + } +} diff --git a/tests/fail/copy_half_a_pointer.stderr b/tests/fail/copy_half_a_pointer.stderr new file mode 100644 index 0000000000..2179775708 --- /dev/null +++ b/tests/fail/copy_half_a_pointer.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to copy parts of a pointer from memory at ALLOC+HALF_PTR + --> $DIR/copy_half_a_pointer.rs:LL:CC + | +LL | let _x = d_alias.read_unaligned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to copy parts of a pointer from memory at ALLOC+HALF_PTR + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: BACKTRACE: + = note: inside `main` at $DIR/copy_half_a_pointer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.rs b/tests/fail/intrinsics/raw_eq_on_ptr.rs index 675b7cf922..c14f86147d 100644 --- a/tests/fail/intrinsics/raw_eq_on_ptr.rs +++ b/tests/fail/intrinsics/raw_eq_on_ptr.rs @@ -6,6 +6,5 @@ extern "rust-intrinsic" { fn main() { let x = &0; - // FIXME: the error message is not great (should be UB rather than 'unsupported') - unsafe { raw_eq(&x, &x) }; //~ERROR: unsupported operation + unsafe { raw_eq(&x, &x) }; //~ERROR: `raw_eq` on bytes with provenance } diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.stderr b/tests/fail/intrinsics/raw_eq_on_ptr.stderr index c6ed1750c0..2236ad9839 100644 --- a/tests/fail/intrinsics/raw_eq_on_ptr.stderr +++ b/tests/fail/intrinsics/raw_eq_on_ptr.stderr @@ -1,10 +1,11 @@ -error: unsupported operation: unable to turn pointer into raw bytes +error: Undefined Behavior: `raw_eq` on bytes with provenance --> $DIR/raw_eq_on_ptr.rs:LL:CC | LL | unsafe { raw_eq(&x, &x) }; - | ^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^ `raw_eq` on bytes with provenance | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside `main` at $DIR/raw_eq_on_ptr.rs:LL:CC diff --git a/tests/fail/invalid_int.rs b/tests/fail/invalid_int.rs index b51af24c13..2435a87a6f 100644 --- a/tests/fail/invalid_int.rs +++ b/tests/fail/invalid_int.rs @@ -1,3 +1,4 @@ +#![allow(invalid_value)] // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation diff --git a/tests/fail/reading_half_a_pointer.rs b/tests/fail/reading_half_a_pointer.rs index a8cdb11f40..2d66913262 100644 --- a/tests/fail/reading_half_a_pointer.rs +++ b/tests/fail/reading_half_a_pointer.rs @@ -24,6 +24,7 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR: unable to turn pointer into raw bytes + let x = *d_alias; + let _val = *x; //~ERROR: is a dangling pointer (it has no provenance) } } diff --git a/tests/fail/reading_half_a_pointer.stderr b/tests/fail/reading_half_a_pointer.stderr index 28cd7cef24..61a7161a98 100644 --- a/tests/fail/reading_half_a_pointer.stderr +++ b/tests/fail/reading_half_a_pointer.stderr @@ -1,10 +1,11 @@ -error: unsupported operation: unable to turn pointer into raw bytes +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/reading_half_a_pointer.rs:LL:CC | -LL | let _x = *d_alias; - | ^^^^^^^^ unable to turn pointer into raw bytes +LL | let _val = *x; + | ^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs deleted file mode 100644 index a60efb98f9..0000000000 --- a/tests/fail/transmute_fat1.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[cfg(target_pointer_width = "64")] -const N: usize = 16; - -#[cfg(target_pointer_width = "32")] -const N: usize = 8; - -fn main() { - let bad = unsafe { - std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - //~^ ERROR: constructing invalid value: encountered a pointer - }; - let _val = bad[0] + bad[bad.len() - 1]; -} diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr deleted file mode 100644 index e1907e0801..0000000000 --- a/tests/fail/transmute_fat1.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - --> $DIR/transmute_fat1.rs:LL:CC - | -LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/validity/invalid_bool_uninit.rs b/tests/fail/validity/invalid_bool_uninit.rs index 84a221a469..ce4fdcabd0 100644 --- a/tests/fail/validity/invalid_bool_uninit.rs +++ b/tests/fail/validity/invalid_bool_uninit.rs @@ -2,9 +2,9 @@ union MyUninit { init: (), - uninit: bool, + uninit: [bool; 1], } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value } diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index 2dbd102d98..5a7bd80e40 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a boolean --> $DIR/invalid_bool_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a boolean | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_char_uninit.rs b/tests/fail/validity/invalid_char_uninit.rs index c16e266490..0e3c3ccac6 100644 --- a/tests/fail/validity/invalid_char_uninit.rs +++ b/tests/fail/validity/invalid_char_uninit.rs @@ -2,9 +2,9 @@ union MyUninit { init: (), - uninit: char, + uninit: [char; 1], } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value } diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index c59bbedd0a..fb5d3ee1f1 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a unicode scalar value --> $DIR/invalid_char_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a unicode scalar value | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_fnptr_uninit.rs b/tests/fail/validity/invalid_fnptr_uninit.rs index c857d83bde..014a8ae847 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.rs +++ b/tests/fail/validity/invalid_fnptr_uninit.rs @@ -2,9 +2,9 @@ union MyUninit { init: (), - uninit: fn(), + uninit: [fn(); 1], } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value } diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index 15ae78e35d..35309e9013 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a function pointer --> $DIR/invalid_fnptr_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a function pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ptr_integer_array_transmute.rs b/tests/fail/validity/ptr_integer_array_transmute.rs deleted file mode 100644 index c8613d274c..0000000000 --- a/tests/fail/validity/ptr_integer_array_transmute.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let r = &mut 42; - let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR: encountered a pointer, but expected plain (non-pointer) bytes -} diff --git a/tests/fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr deleted file mode 100644 index 118c6a4327..0000000000 --- a/tests/fail/validity/ptr_integer_array_transmute.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - --> $DIR/ptr_integer_array_transmute.rs:LL:CC - | -LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index fecc02d7a5..045bb46464 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -1,8 +1,9 @@ -#![allow(deprecated)] +#![allow(deprecated, invalid_value)] // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { // Deliberately using `mem::uninitialized` to make sure that despite all the mitigations, we consider this UB. - let _val: f32 = unsafe { std::mem::uninitialized() }; + // The array avoids a `Scalar` layout which detects uninit without even doing validation. + let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index c64f56e255..677a0fc557 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes --> $DIR/uninit_float.rs:LL:CC | -LL | let _val: f32 = unsafe { std::mem::uninitialized() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs index a9b2007326..a94302603a 100644 --- a/tests/fail/validity/uninit_integer.rs +++ b/tests/fail/validity/uninit_integer.rs @@ -1,6 +1,8 @@ +#![allow(invalid_value)] // This test is from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { - let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + // The array avoids a `Scalar` layout which detects uninit without even doing validation. + let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index 5828eba793..a9ac2a6dc6 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes --> $DIR/uninit_integer.rs:LL:CC | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_raw_ptr.rs b/tests/fail/validity/uninit_raw_ptr.rs index 9f99dc1a0e..18703152ea 100644 --- a/tests/fail/validity/uninit_raw_ptr.rs +++ b/tests/fail/validity/uninit_raw_ptr.rs @@ -1,4 +1,7 @@ +#![allow(invalid_value)] + fn main() { - let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; + // The array avoids a `Scalar` layout which detects uninit without even doing validation. + let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() }; //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_raw_ptr.stderr b/tests/fail/validity/uninit_raw_ptr.stderr index 68f7d2af6a..bbae9cf69f 100644 --- a/tests/fail/validity/uninit_raw_ptr.stderr +++ b/tests/fail/validity/uninit_raw_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer --> $DIR/uninit_raw_ptr.rs:LL:CC | -LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs deleted file mode 100644 index dfd78ace52..0000000000 --- a/tests/pass/transmute_fat.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. -//@compile-flags: -Zmiri-disable-stacked-borrows - -fn main() { - // If we are careful, we can exploit data layout... - // This is a tricky case since we are transmuting a ScalarPair type to a non-ScalarPair type. - let raw = unsafe { std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; - let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; - assert_eq!(unsafe { *ptr }, 42); -} diff --git a/tests/pass/transmute_ptr.rs b/tests/pass/transmute_ptr.rs new file mode 100644 index 0000000000..fd9d457e44 --- /dev/null +++ b/tests/pass/transmute_ptr.rs @@ -0,0 +1,52 @@ +#![feature(strict_provenance)] +use std::{mem, ptr}; + +fn t1() { + // If we are careful, we can exploit data layout... + // This is a tricky case since we are transmuting a ScalarPair type to a non-ScalarPair type. + let raw = unsafe { mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; + let ptr: *const u8 = unsafe { mem::transmute_copy(&raw) }; + assert_eq!(unsafe { *ptr }, 42); +} + +#[cfg(target_pointer_width = "64")] +const PTR_SIZE: usize = 8; +#[cfg(target_pointer_width = "32")] +const PTR_SIZE: usize = 4; + +fn t2() { + let bad = unsafe { mem::transmute::<&[u8], [u8; 2 * PTR_SIZE]>(&[1u8]) }; + let _val = bad[0] + bad[bad.len() - 1]; +} + +fn ptr_integer_array() { + let r = &mut 42; + let _i: [usize; 1] = unsafe { mem::transmute(r) }; + + let _x: [u8; PTR_SIZE] = unsafe { mem::transmute(&0) }; +} + +fn ptr_in_two_halves() { + unsafe { + let ptr = &0 as *const i32; + let arr = [ptr; 2]; + // We want to do a scalar read of a pointer at offset PTR_SIZE/2 into this array. But we + // cannot use a packed struct or `read_unaligned`, as those use the memcpy code path in + // Miri. So instead we shift the entire array by a bit and then the actual read we want to + // do is perfectly aligned. + let mut target_arr = [ptr::null::(); 3]; + let target = target_arr.as_mut_ptr().cast::(); + target.add(PTR_SIZE / 2).cast::<[*const i32; 2]>().write_unaligned(arr); + // Now target_arr[1] is a mix of the two `ptr` we had stored in `arr`. + let strange_ptr = target_arr[1]; + // Check that the provenance works out. + assert_eq!(*strange_ptr.with_addr(ptr.addr()), 0); + } +} + +fn main() { + t1(); + t2(); + ptr_integer_array(); + ptr_in_two_halves(); +}